caddyserver/caddy · error
encoder already added: %s
Error message
encoder already added: %s
What it means
Returned by addEncoding when a second encoder registers the same Accept-Encoding token as one already in enc.writerPools. Each token may map to exactly one encoder per encode handler.
Source
Thrown at modules/caddyhttp/encode/encode.go:209
err := next.ServeHTTP(w, r)
// If there was an error, disable encoding completely
// This prevents corruption when handle_errors processes the response
if err != nil {
if ew, ok := w.(*responseWriter); ok {
ew.disabled = true
}
}
return err
}
func (enc *Encode) addEncoding(e Encoding) error {
ae := e.AcceptEncoding()
if ae == "" {
return fmt.Errorf("encoder does not specify an Accept-Encoding value")
}
if _, ok := enc.writerPools[ae]; ok {
return fmt.Errorf("encoder already added: %s", ae)
}
if enc.writerPools == nil {
enc.writerPools = make(map[string]*sync.Pool)
}
enc.writerPools[ae] = &sync.Pool{
New: func() any {
return e.NewEncoder()
},
}
return nil
}
// openResponseWriter creates a new response writer that may (or may not)
// encode the response with encodingName. The returned response writer MUST
// be closed after the handler completes.
func (enc *Encode) openResponseWriter(encodingName string, w http.ResponseWriter, isConnect bool) *responseWriter {
var rw responseWriter
return enc.initResponseWriter(&rw, encodingName, w, isConnect)View on GitHub (pinned to 50e54ee279)
Solutions
- Give each encoder a distinct AcceptEncoding() token
- Remove one of the colliding encoders from the config
- Check caddy list-modules for two modules registering overlapping encodings
Example fix
// before
func (A) AcceptEncoding() string { return "gzip" } // collides with stdlib gzip
// after
func (A) AcceptEncoding() string { return "gzip2" } Defensive patterns
Strategy: validation
Validate before calling
// plugin self-check in tests: token not already used by stdlib
func TestAcceptEncodingUnique(t *testing.T) {
for _, taken := range []string{"gzip", "zstd"} {
if MyEnc{}.AcceptEncoding() == taken { t.Fatal("token collision") }
}
} Prevention
- Namespace custom encoder tokens to avoid collisions
- Don't register two modules for the same encoding
When it happens
Trigger: Two encoder modules both claiming "gzip" loaded into the same encode config; e.g. a plugin that wraps gzip but reuses the same token.
Common situations: A custom re-implementation of an existing encoder that didn't pick a new token; two plugins colliding.
Related errors
- adding encoding %s: %v
- encoder does not specify an Accept-Encoding value
- [%s] key already exists: %s
- server listening on %v is HTTP, but attempts to configure TL
- two policies with same match criteria have conflicting ALPN:
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/3bcc0deb7d764a33.
Report an issue: GitHub.