caddyserver/caddy · critical
expected ModuleMap because inline_key is empty; but we do no
Error message
expected ModuleMap because inline_key is empty; but we do not recognize this type: %s
What it means
In loadModulesFromSomeMap, when the caddy tag has no inline_key, the field's map type must be a caddy.ModuleMap — its keys are the module names. If the field is a plain map[string]json.RawMessage (or other map type) and inline_key is empty, Caddy panics because map keys cannot be trusted to be module names. It is a type/tag mismatch in the module's source.
Source
Thrown at context.go:305
}
// emitEvent is a small convenience method so the caddy core can emit events, if the event app is configured.
func (ctx Context) emitEvent(name string, data map[string]any) Event {
if ctx.cfg == nil || ctx.cfg.eventEmitter == nil {
return Event{}
}
return ctx.cfg.eventEmitter.Emit(ctx, name, data)
}
// loadModulesFromSomeMap loads modules from val, which must be a type of map[string]any.
// Depending on inlineModuleKey, it will be interpreted as either a ModuleMap (key is the module
// name) or as a regular map (key is not the module name, and module name is defined inline).
func (ctx Context) loadModulesFromSomeMap(namespace, inlineModuleKey string, val reflect.Value) (map[string]any, error) {
// if no inline_key is specified, then val must be a ModuleMap,
// where the key is the module name
if inlineModuleKey == "" {
if !isModuleMapType(val.Type()) {
panic(fmt.Sprintf("expected ModuleMap because inline_key is empty; but we do not recognize this type: %s", val.Type()))
}
return ctx.loadModuleMap(namespace, val)
}
// otherwise, val is a map with modules, but the module name is
// inline with each value (the key means something else)
return ctx.loadModulesFromRegularMap(namespace, inlineModuleKey, val)
}
// loadModulesFromRegularMap loads modules from val, where val is a map[string]json.RawMessage.
// Map keys are NOT interpreted as module names, so module names are still expected to appear
// inline with the objects.
func (ctx Context) loadModulesFromRegularMap(namespace, inlineModuleKey string, val reflect.Value) (map[string]any, error) {
mods := make(map[string]any)
iter := val.MapRange()
for iter.Next() {
k := iter.Key()
v := iter.Value()View on GitHub (pinned to 50e54ee279)
Solutions
- Change the field type to caddy.ModuleMap so keys are interpreted as module names
- Or keep map[string]json.RawMessage and add inline_key to the tag, embedding the module name inside each value object
- Re-run provisioning after fixing to confirm the map values carry valid module names
Example fix
// before
type Handler struct {
Matchers map[string]json.RawMessage `json:"match,omitempty" caddy:"namespace=http.matchers"`
}
// after
import "github.com/caddyserver/caddy/v2"
type Handler struct {
Matchers caddy.ModuleMap `json:"match,omitempty" caddy:"namespace=http.matchers"`
} Defensive patterns
Strategy: type-guard
Validate before calling
import "reflect"
func isModuleMap(t reflect.Type) bool {
return t == reflect.TypeOf(caddy.ModuleMap{})
} Type guard
// use the concrete type directly so a wrong declaration cannot compile-land silently
type MyHandler struct {
Matchers caddy.ModuleMap `json:"match,omitempty" caddy:"namespace=http.matchers"`
} Try / catch
defer func() { if r := recover(); r != nil { err = fmt.Errorf("loadModulesFromSomeMap: %v", r) } }() Prevention
- Without inline_key, declare the field as caddy.ModuleMap
- With plain map[string]json.RawMessage, always add inline_key
- Test both JSON shapes your module accepts
When it happens
Trigger: Declaring a field as map[string]json.RawMessage with a tag lacking inline_key (e.g. `caddy:"namespace=http.handlers"`) and calling ctx.LoadModule.
Common situations: Custom modules using a generic map instead of caddy.ModuleMap; refactoring a ModuleMap field into a plain map and dropping inline_key; imitating upstream code with the wrong map type.
Related errors
- malformed tag on field %s: %v
- missing 'namespace' key in struct tag on field %s
- unable to determine module name without inline_key when type
- unable to determine module name without inline_key because t
- module ID missing
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/2533d826ddd7f0ce.
Report an issue: GitHub.