caddyserver/caddy · critical
unable to determine module name without inline_key because t
Error message
unable to determine module name without inline_key because type is not a ModuleMap
What it means
Same contract as for a single json.RawMessage, but the field is a []json.RawMessage (slice of raw module configs). Each element needs an inline module name, so the tag must declare inline_key; without it LoadModule panics because it cannot derive module names. This is a compile-time-visible design mistake in the module struct.
Source
Thrown at context.go:227
switch val.Kind() {
case reflect.Slice:
if isJSONRawMessage(typ) {
// val is `json.RawMessage` ([]uint8 under the hood)
if inlineModuleKey == "" {
panic("unable to determine module name without inline_key when type is not a ModuleMap")
}
val, err := ctx.loadModuleInline(inlineModuleKey, moduleNamespace, val.Interface().(json.RawMessage))
if err != nil {
return nil, err
}
result = val
} else if isJSONRawMessage(typ.Elem()) {
// val is `[]json.RawMessage`
if inlineModuleKey == "" {
panic("unable to determine module name without inline_key because type is not a ModuleMap")
}
var all []any
for i := 0; i < val.Len(); i++ {
val, err := ctx.loadModuleInline(inlineModuleKey, moduleNamespace, val.Index(i).Interface().(json.RawMessage))
if err != nil {
return nil, fmt.Errorf("position %d: %v", i, err)
}
all = append(all, val)
}
result = all
} else if typ.Elem().Kind() == reflect.Slice && isJSONRawMessage(typ.Elem().Elem()) {
// val is `[][]json.RawMessage`
if inlineModuleKey == "" {
panic("unable to determine module name without inline_key because type is not a ModuleMap")
}
var all [][]any
for i := 0; i < val.Len(); i++ {View on GitHub (pinned to 50e54ee279)
Solutions
- Add inline_key to the struct tag so each JSON element carries its module name
- Or switch the field type to caddy.ModuleMap / caddy.ModuleMap-based types when map keys should name modules
- Validate that every element of the JSON array contains the inline_key property
Example fix
// before
type Route struct {
Matchers []json.RawMessage `json:"match,omitempty" caddy:"namespace=http.matchers"`
}
// after
type Route struct {
Matchers []json.RawMessage `json:"match,omitempty" caddy:"namespace=http.matchers inline_key=matcher"`
} Defensive patterns
Strategy: validation
Validate before calling
func requireSliceInlineKey(ptr any, fieldName string) error {
f, _ := reflect.TypeOf(ptr).Elem().FieldByName(fieldName)
if f.Type.Kind() == reflect.Slice && f.Type.Elem() == reflect.TypeOf(json.RawMessage{}) {
opts, _ := caddy.ParseStructTag(f.Tag.Get("caddy"))
if opts["inline_key"] == "" {
return fmt.Errorf("%s is []json.RawMessage; needs inline_key", fieldName)
}
}
return nil
} Try / catch
defer func() { if r := recover(); r != nil { err = fmt.Errorf("LoadModule: %v", r) } }() Prevention
- Slices of raw JSON require inline_key
- Validate JSON elements contain the inline key before provisioning
- Mirror caddyhttp's matcher patterns for ordered lists
When it happens
Trigger: Declaring a field as []json.RawMessage whose tag lacks inline_key, e.g. `caddy:"namespace=http.matchers"`, then calling ctx.LoadModule.
Common situations: Custom modules holding a list of matcher/handler blobs; converting a ModuleMap list to a raw-message slice for ordering guarantees while keeping the old tag.
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
- expected ModuleMap because inline_key is empty; but we do no
- module ID missing
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/a7dbb859e2379e52.
Report an issue: GitHub.