{"record":{"id":"d6c98fa3d764e020","repo":"caddyserver/caddy","slug":"unable-to-determine-module-name-without-inline-key","errorCode":null,"errorMessage":"unable to determine module name without inline_key when type is not a ModuleMap","messagePattern":"unable to determine module name without inline_key when type is not a ModuleMap","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"context.go","lineNumber":216,"sourceCode":"\tif err != nil {\n\t\tpanic(fmt.Sprintf(\"malformed tag on field %s: %v\", fieldName, err))\n\t}\n\n\tmoduleNamespace, ok := opts[\"namespace\"]\n\tif !ok {\n\t\tpanic(fmt.Sprintf(\"missing 'namespace' key in struct tag on field %s\", fieldName))\n\t}\n\tinlineModuleKey := opts[\"inline_key\"]\n\n\tvar result any\n\n\tswitch val.Kind() {\n\tcase reflect.Slice:\n\t\tif isJSONRawMessage(typ) {\n\t\t\t// val is `json.RawMessage` ([]uint8 under the hood)\n\n\t\t\tif inlineModuleKey == \"\" {\n\t\t\t\tpanic(\"unable to determine module name without inline_key when type is not a ModuleMap\")\n\t\t\t}\n\t\t\tval, err := ctx.loadModuleInline(inlineModuleKey, moduleNamespace, val.Interface().(json.RawMessage))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tresult = val\n\t\t} else if isJSONRawMessage(typ.Elem()) {\n\t\t\t// val is `[]json.RawMessage`\n\n\t\t\tif inlineModuleKey == \"\" {\n\t\t\t\tpanic(\"unable to determine module name without inline_key because type is not a ModuleMap\")\n\t\t\t}\n\t\t\tvar all []any\n\t\t\tfor i := 0; i < val.Len(); i++ {\n\t\t\t\tval, err := ctx.loadModuleInline(inlineModuleKey, moduleNamespace, val.Index(i).Interface().(json.RawMessage))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"position %d: %v\", i, err)\n\t\t\t\t}","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/context.go#L198-L234","documentation":"When a field is declared as json.RawMessage (a single raw JSON blob), LoadModule must find the module name inline inside the JSON, which requires the tag to declare inline_key. With no inline_key and a non-ModuleMap type, Caddy has no way to know which module to instantiate, so it panics. This is an API-contract violation between the field's type and its struct tag.","triggerScenarios":"Declaring a field as json.RawMessage with a tag like `caddy:\"namespace=http.handlers\"` (no inline_key) and calling ctx.LoadModule on it.","commonSituations":"Custom modules that want flexible inline module specs (like Caddyfile-matched matchers); porting a ModuleMap field to json.RawMessage without updating the tag; following an example that omitted inline_key.","solutions":["Add inline_key to the tag: `caddy:\"namespace=http.matchers inline_key=matcher\"`, where the JSON object must then contain that key naming the module","Or change the field type to caddy.ModuleMap if the map key should be the module name","Ensure the JSON config actually includes the inline_key field with a valid module name"],"exampleFix":"// before\ntype Route struct {\n    Matcher json.RawMessage `json:\"matcher,omitempty\" caddy:\"namespace=http.matchers\"`\n}\n// after\ntype Route struct {\n    Matcher json.RawMessage `json:\"matcher,omitempty\" caddy:\"namespace=http.matchers inline_key=matcher\"`\n}","handlingStrategy":"validation","validationCode":"import \"reflect\"\n\nfunc requireInlineKey(ptr any, fieldName string) error {\n    f, _ := reflect.TypeOf(ptr).Elem().FieldByName(fieldName)\n    t := f.Type\n    raw := t == reflect.TypeOf(json.RawMessage{})\n    if raw {\n        opts, _ := caddy.ParseStructTag(f.Tag.Get(\"caddy\"))\n        if opts[\"inline_key\"] == \"\" {\n            return fmt.Errorf(\"%s is json.RawMessage; its caddy tag needs inline_key\", fieldName)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"defer func() { if r := recover(); r != nil { err = fmt.Errorf(\"LoadModule: %v\", r) } }()","preventionTips":["json.RawMessage fields always need inline_key in the tag","Prefer caddy.ModuleMap when keys should name modules","Unit-test config unmarshal + provision for each new field"],"tags":["caddy","go","module-system","struct-tag","panic"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}