{"record":{"id":"b4a59d7535cd941a","repo":"caddyserver/caddy","slug":"malformed-tag-on-field-s-v","errorCode":null,"errorMessage":"malformed tag on field %s: %v","messagePattern":"malformed tag on field (.+?): (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"context.go","lineNumber":199,"sourceCode":"// to type-assert each 'any' value(s) to the types that are useful to you\n// and store them on the same struct. Storing them on the same struct makes for\n// easy garbage collection when your host module is no longer needed.\n//\n// Loaded modules have already been provisioned and validated. Upon returning\n// successfully, this method clears the json.RawMessage(s) in the field since\n// the raw JSON is no longer needed, and this allows the GC to free up memory.\nfunc (ctx Context) LoadModule(structPointer any, fieldName string) (any, error) {\n\tval := reflect.ValueOf(structPointer).Elem().FieldByName(fieldName)\n\ttyp := val.Type()\n\n\tfield, ok := reflect.TypeOf(structPointer).Elem().FieldByName(fieldName)\n\tif !ok {\n\t\tpanic(fmt.Sprintf(\"field %s does not exist in %#v\", fieldName, structPointer))\n\t}\n\n\topts, err := ParseStructTag(field.Tag.Get(\"caddy\"))\n\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}","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/context.go#L181-L217","documentation":"Caddy's Context.LoadModule reads the `caddy:\"...\"` struct tag on a module field to learn how to load nested modules. ParseStructTag failed to parse that tag, which is a programming error in the module's source code, not a runtime/config problem. Because this is a panic, it crashes the process at provisioning time when the field is loaded.","triggerScenarios":"Calling ctx.LoadModule(&handler, \"Field\") where Field's struct tag is malformed, e.g. `caddy:\"namespace=http.handlers\"` (missing value), unbalanced quotes, or a tag not made of key=value pairs.","commonSituations":"Writing a custom Caddy module and hand-typing the caddy struct tag; copy-pasting a tag from another field and breaking the syntax; typos like `caddy:\"namespace=http.handlers inline_key=module\"` with stray characters.","solutions":["Fix the struct tag so it is valid key=value pairs: `caddy:\"namespace=http.handlers\"` or `caddy:\"namespace=http.handlers inline_key=handler\"`","Verify the tag string with go vet / structtag linters which catch malformed tags at compile time","Confirm the tag is on the exact field name passed to LoadModule"],"exampleFix":"// before\ntype Handler struct {\n    Upstream *json.RawMessage `json:\"upstream\" caddy:\"namespace=http.reverse_proxy.upstreams\"` // missing closing quote in tag content\n}\n// after\ntype Handler struct {\n    Upstream *json.RawMessage `json:\"upstream\" caddy:\"namespace=http.reverse_proxy.upstreams\"`\n}","handlingStrategy":"validation","validationCode":"// before LoadModule, parse the tag yourself to fail fast with a clear error\nimport \"reflect\"\n\nfunc validateCaddyTag(ptr any, fieldName string) error {\n    f, ok := reflect.TypeOf(ptr).Elem().FieldByName(fieldName)\n    if !ok {\n        return fmt.Errorf(\"field %s missing\", fieldName)\n    }\n    if _, err := caddy.ParseStructTag(f.Tag.Get(\"caddy\")); err != nil {\n        return fmt.Errorf(\"bad tag on %s: %w\", fieldName, err)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"// last resort in module plumbing: wrap provisioning in a recover\nfunc safeLoad(ctx caddy.Context, ptr any, field string) (m any, err error) {\n    defer func() {\n        if r := recover(); r != nil {\n            err = fmt.Errorf(\"LoadModule panic: %v\", r)\n        }\n    }()\n    return ctx.LoadModule(ptr, field)\n}","preventionTips":["Run go vet on every build; it flags malformed struct tags","Keep a working upstream module open as tag reference","Add a unit test that calls LoadModule on each custom 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-15T22:17:37.221Z"}