caddyserver/caddy · error
decoding module config: %s: %v
Error message
decoding module config: %s: %v
What it means
After instantiating a module, LoadModuleByID decodes the user's JSON into it with caddy.StrictUnmarshalJSON, which uses DisallowUnknownFields. Any JSON that does not match the module's struct — unknown keys, wrong value types, malformed syntax — produces 'decoding module config: %s: %v' where %s is the ModuleInfo and %v is the encoding/json error including the offending field path.
Source
Thrown at context.go:392
}
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)
}
// fill in its config only if there is a config to fill in
if len(rawMsg) > 0 {
err := StrictUnmarshalJSON(rawMsg, &val)
if err != nil {
return nil, fmt.Errorf("decoding module config: %s: %v", modInfo, err)
}
}
if val == nil {
// returned module values are almost always type-asserted
// before being used, so a nil value would panic; and there
// is no good reason to explicitly declare null modules in
// a config; it might be because the user is trying to achieve
// a result the developer isn't expecting, which is a smell
return nil, fmt.Errorf("module value cannot be null")
}
var err error
// if this is an app module, keep a reference to it,
// since submodules may need to reference it during
// provisioning (even though the parent app module
// may not be fully provisioned yet; this is the caseView on GitHub (pinned to 50e54ee279)
Solutions
- Read the tail of the message: encoding/json errors name the unknown/invalid field (e.g. 'unknown field "responce"')
- Check the module's documented JSON schema (https://caddyserver.com/docs/json/ or module docs) and correct the field name/type
- Remove custom/legacy fields that no longer exist in the module version you run
- Prefer adapting from Caddyfile (`caddy adapt`) so field names are generated correctly, then validate with `caddy validate`
Example fix
// before
{ "handler": "static_response", "responce": "hi" }
// after
{ "handler": "static_response", "body": "hi" } Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight with the same strict decoder Caddy uses
if err := json.Unmarshal(raw, &target); err != nil {
// catches syntax/type errors early; strict unknown-field check:
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&target); err != nil { return err }
} Try / catch
if _, err := ctx.LoadModuleByID(id, raw); err != nil {
return fmt.Errorf("config for %s rejected: %w", id, err) // inner error names the unknown field
} Prevention
- Use `caddy adapt` to generate JSON with correct field names
- Check module docs for field names/types before hand-editing JSON
- Encode durations as strings ("30s"), arrays as arrays
When it happens
Trigger: Supplying a config object with a field the module struct does not define (e.g. "body" vs "contents"), a string where a duration/array is expected, or trailing syntax errors; StrictUnmarshalJSON rejects it and LoadModuleByID wraps the failure with the module identity.
Common situations: Hand-written JSON using guessed field names; configs migrated from older Caddy versions where fields were renamed (respond "body" → "body" vs older "contents"); forgetting that durations must be strings like "30s"; copying examples for a different module version.
Related errors
- position %d: %v
- key %s: %v
- loading module '%s': %v
- decoding request body: %w, at offset %d
- decoding request body: %w
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/8dfe8144e5395912.
Report an issue: GitHub.