Repository: go
Issue: proposal: net/http: return an error instead of panicking on http.ServeMux registration errors
Labels: Proposal

This will fall into the Go 2 category bucket, because as proposed it is a [breaking behavioral change for Go 1](https://go.dev/doc/go1compat).

## Proposal

Instead of panicking on invalid `http.Handler` registrations, `(*http.ServeMux).Handle` should return errors.  This is germane in when the user attempts to register multiple `http.Handler` against the same path as demonstrated with `http.DefaultServeMux`:
   
```
http.Handle("/path", h)
http.Handle("/path", h)

// Output:
panic: http: multiple registrations for /path
```

Instead, I propose `(*http.ServeMux).Handle` gets a new method signature similar to this:

```
func (*http.ServeMux) Handle(string, Handler) error { ... }
```
 
In the case above, a sentinel or structured error value could be returned by `package http` to enable callers to handle the error:

```
package http

var ErrMultipleRegistrations = errors.New("http: more than one handler registered against the path")

// Or:

type MultipleRegistrationError struct {
  Path string
}

func (err *MultipleRegistrationError) Error() string { ... }
```

## Motivation

> Why is this panic worth handling at all?  Shouldn't the user know about all registrations and be able to prevent multiple?

I believe the latter question is the first to start with.  Based on our team's experience in offering a server framework used internally by several thousand customer teams, we got to see first-hand how the multiple registration behavior played in a gigantic monorepo, especially when combined with code that registered default debugging handlers using `http.Handle` in `func init` bodies.  It played out terribly.  This was because there were two registration pathways:

1. through the server framework directly, which could catch duplicates of thing registered through it
2. things registered directly by other infrastructure providers in `func init` on `http.DefaultServeMux` using `http.Handle` and similar

We could only control no. 1.  Auditing no. 2 was a boil-the-ocean affair, particularly because there was no wisdom nor enforcement of avoiding mutating package state in registrations.  Attempting to convert no. 2 to support per-`http.ServeMux` registration was a good compromise, but we could never catch up with the codebase.

In effect, this means that it's infeasible in large codebases to ensure that there is central control over who is registering what.  We tried with a per-server `http.ServeMux` that falls back to `http.DefaultServeMux` for paths it doesn't recognize, but the result and behavior is not pretty.  It's also error-prone.

Returning an error sentinel or structured error value would enable intermediate frameworks and middleware to more gracefully handle such cases, which is a huge win for developer experience.

## Other Thoughts and Speculation

An API for unregistering existing handlers might be interesting to consider.  A server framework could de-register a duplicate.  Or as a twist on this, last-one-wins semantic for registration?  I haven't thought about these super closely, but I can say the `panic` should go.

Perhaps a structured error return (as suggested above) could return information about the registrations: what package, what line, identifier type information, or interface value of the pre-existing `http.Handler`.