caddyserver/caddy · error
module %s is not precompressor
Error message
module %s is not precompressor
What it means
Returned in FileServer.Provision when a module loaded under the precompressed namespace does not implement the encode.Precompressed interface. The precompressed slot has a module type contract (AcceptEncoding/Suffix methods); a module that registers itself under that namespace but lacks the interface trips this check.
Source
Thrown at modules/caddyhttp/fileserver/staticfiles.go:229
// for hide paths that are static (i.e. no placeholders), we can transform them into
// absolute paths before the server starts for very slight performance improvement
for i, h := range fsrv.Hide {
if !strings.Contains(h, "{") && strings.Contains(h, separator) {
if abs, err := caddy.FastAbs(h); err == nil {
fsrv.Hide[i] = abs
}
}
}
// support precompressed sidecar files
mods, err := ctx.LoadModule(fsrv, "PrecompressedRaw")
if err != nil {
return fmt.Errorf("loading encoder modules: %v", err)
}
for modName, modIface := range mods.(map[string]any) {
p, ok := modIface.(encode.Precompressed)
if !ok {
return fmt.Errorf("module %s is not precompressor", modName)
}
ae := p.AcceptEncoding()
if ae == "" {
return fmt.Errorf("precompressor does not specify an Accept-Encoding value")
}
suffix := p.Suffix()
if suffix == "" {
return fmt.Errorf("precompressor does not specify a Suffix value")
}
if _, ok := fsrv.precompressors[ae]; ok {
return fmt.Errorf("precompressor already added: %s", ae)
}
if fsrv.precompressors == nil {
fsrv.precompressors = make(map[string]encode.Precompressed)
}
fsrv.precompressors[ae] = p
}
View on GitHub (pinned to 50e54ee279)
Solutions
- Check the failing module name in the error and ensure it implements AcceptEncoding() string and Suffix() string (the full encode.Precompressed interface).
- Fix the module's CaddyModule() ID to the correct namespace and rebuild with xcaddy.
- Rebuild the plugin against the same Caddy version as the server binary to avoid interface drift.
- Remove the incompatible module from the build or from the precompressed config.
Example fix
// before: module registered without implementing the full interface
func (Foo) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ID: "http.precompressed.foo", New: func() caddy.Module { return new(Foo) }} }
// after
var _ encode.Precompressed = (*Foo)(nil) // compile-time guard
func (Foo) AcceptEncoding() string { return "foo" }
func (Foo) Suffix() string { return ".foo" } Defensive patterns
Strategy: type-guard
Type guard
// Compile-time guard in your plugin: fails the build if the interface drifts var _ encode.Precompressed = (*MyPrecompressor)(nil)
Prevention
- Always declare interface guards for Caddy module contracts in plugins.
- Build plugins against the exact Caddy version used in production (xcaddy with a pinned core version).
- Smoke-test custom modules with `caddy validate` on a minimal config before shipping.
When it happens
Trigger: Loading a third-party or custom module whose CaddyModule ID is in the http.precompressed namespace but which does not implement encode.Precompressed (e.g. wrong method set, or registered under the wrong ID by mistake).
Common situations: Writing a custom precompressor plugin and registering it with an incorrect module ID; a plugin built against an older Caddy API where the Precompressed interface differed; type mismatch after an API refactor between Caddy versions.
Related errors
- precompressor does not specify an Accept-Encoding value
- precompressor does not specify a Suffix value
- getting module named '%s': %v
- module %s is not a precompressor; is %T
- loading encoder modules: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/c25d89458846efd5.
Report an issue: GitHub.