caddyserver/caddy · error
unknown module: %s
Error message
unknown module: %s
What it means
LoadModuleByID looks the requested module ID up in the global registry populated by caddy.RegisterModule (usually via plugin init() functions and modules/standard/imports.go). If the ID is absent it returns 'unknown module: %s'. Common root causes: the plugin is not compiled into this binary, the ID is misspelled, or the namespace/name doesn't match what was registered.
Source
Thrown at context.go:369
return all, nil
}
// LoadModuleByID decodes rawMsg into a new instance of mod and
// returns the value. If mod.New is nil, an error is returned.
// If the module implements Validator or Provisioner interfaces,
// those methods are invoked to ensure the module is fully
// configured and valid before being used.
//
// This is a lower-level method and will usually not be called
// directly by most modules. However, this method is useful when
// dynamically loading/unloading modules in their own context,
// like from embedded scripts, etc.
func (ctx Context) LoadModuleByID(id string, rawMsg json.RawMessage) (any, error) {
modulesMu.RLock()
modInfo, ok := modules[id]
modulesMu.RUnlock()
if !ok {
return nil, fmt.Errorf("unknown module: %s", id)
}
if modInfo.New == nil {
return nil, fmt.Errorf("module '%s' has no constructor", modInfo.ID)
}
val := modInfo.New()
// value must be a pointer for unmarshaling into concrete type, even if
// the module's concrete type is a slice or map; New() *should* return
// a pointer, otherwise unmarshaling errors or panics will occur
if rv := reflect.ValueOf(val); rv.Kind() != reflect.Pointer {
log.Printf("[WARNING] ModuleInfo.New() for module '%s' did not return a pointer,"+
" so we are using reflection to make a pointer instead; please fix this by"+
" using new(Type) or &Type notation in your module's New() function.", id)
val = reflect.New(rv.Type()).Elem().Addr().Interface().(Module)
}
View on GitHub (pinned to 50e54ee279)
Solutions
- Run `caddy list-modules` and confirm the exact module ID exists in this build; compare character-for-character with the error
- If it is a plugin module, build a custom binary: `xcaddy build --with github.com/user/plugin`
- Correct the namespace in the config or in the code building the ID (e.g. the caddy:"module=..." tag or the moduleScope passed to loadModuleInline)
- Pin matching versions: ensure the plugin version supports your Caddy version's module ID scheme
Example fix
// before xcaddy build # forgot --with, then config references http.handlers.my_plugin // after xcaddy build --with github.com/user/caddy-myplugin
Defensive patterns
Strategy: validation
Validate before calling
// Guard LoadModuleByID calls with a registry check
if !moduleRegistered("http.handlers.foo") {
return fmt.Errorf("cannot proceed: build custom caddy with the foo plugin")
}
val, err := ctx.LoadModuleByID("http.handlers.foo", raw) Type guard
func moduleRegistered(id string) bool {
for _, m := range caddy.Modules() {
if m == id { return true }
}
return false
} Try / catch
val, err := ctx.LoadModuleByID(id, raw)
if err != nil {
if strings.Contains(err.Error(), "unknown module") {
// registry problem: fix build or ID, do not retry
}
return err
} Prevention
- Run `caddy list-modules` on the target binary before writing configs
- Include every needed plugin in `xcaddy build --with ...`
- Prefix module IDs with the correct namespace (e.g. http.handlers., dns., tls.)
When it happens
Trigger: Calling ctx.LoadModuleByID("http.handlers.foo", raw) where no module with that exact ID was registered — plugin not imported, custom build missing it, or the ID string constructed with the wrong namespace/scope (e.g. concatenating an empty moduleScope producing '.foo').
Common situations: Deploying a JSON config produced elsewhere to a stock Caddy binary that lacks third-party plugins; upgrading Caddy where a plugin's module ID changed; typos in module IDs in hand-written JSON; empty namespace producing malformed IDs when loading inline modules.
Related errors
- module name '%s': %v
- module ID missing
- missing ModuleInfo.New
- ModuleInfo.New must return a non-nil module instance
- encoding new config: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/5e1d48d8ca1f2c10.
Report an issue: GitHub.