caddyserver/caddy · critical
missing 'namespace' key in struct tag on field %s
Error message
missing 'namespace' key in struct tag on field %s
What it means
Context.LoadModule requires the field's `caddy:"..."` struct tag to contain a `namespace` key so it knows which module namespace to instantiate from (e.g. http.handlers). The tag parsed successfully but had no namespace entry, so Caddy cannot resolve candidate modules. This is a source-code defect in the module definition and panics at provision time.
Source
Thrown at context.go:204
// successfully, this method clears the json.RawMessage(s) in the field since
// the raw JSON is no longer needed, and this allows the GC to free up memory.
func (ctx Context) LoadModule(structPointer any, fieldName string) (any, error) {
val := reflect.ValueOf(structPointer).Elem().FieldByName(fieldName)
typ := val.Type()
field, ok := reflect.TypeOf(structPointer).Elem().FieldByName(fieldName)
if !ok {
panic(fmt.Sprintf("field %s does not exist in %#v", fieldName, structPointer))
}
opts, err := ParseStructTag(field.Tag.Get("caddy"))
if err != nil {
panic(fmt.Sprintf("malformed tag on field %s: %v", fieldName, err))
}
moduleNamespace, ok := opts["namespace"]
if !ok {
panic(fmt.Sprintf("missing 'namespace' key in struct tag on field %s", fieldName))
}
inlineModuleKey := opts["inline_key"]
var result any
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 = valView on GitHub (pinned to 50e54ee279)
Solutions
- Add the namespace to the struct tag: `caddy:"namespace=<your.namespace>"` using the same namespace as the registered module IDs
- Check the module ID you registered via caddy.RegisterModule and use everything before the last dot as the namespace
- Compare against a working upstream module's tag (e.g. caddyhttp handler fields)
Example fix
// before
type Middleware struct {
Matcher json.RawMessage `json:"match,omitempty" caddy:"inline_key=matcher"`
}
// after
type Middleware struct {
Matcher json.RawMessage `json:"match,omitempty" caddy:"namespace=http.matchers.inline_key=matcher"` // ensure correct: namespace=http.matchers plus inline_key
} Defensive patterns
Strategy: validation
Validate before calling
import "reflect"
func requireNamespaceTag(ptr any, fieldName string) error {
f, _ := reflect.TypeOf(ptr).Elem().FieldByName(fieldName)
opts, err := caddy.ParseStructTag(f.Tag.Get("caddy"))
if err != nil {
return err
}
if _, ok := opts["namespace"]; !ok {
return fmt.Errorf("field %s: caddy tag must declare namespace", fieldName)
}
return nil
} Try / catch
defer func() { if r := recover(); r != nil { err = fmt.Errorf("LoadModule: %v", r) } }() Prevention
- Namespace must equal the registered module ID minus the last segment
- Test provisioning of new modules in CI
- Never ship struct tags written from memory alone; copy a known-good one
When it happens
Trigger: Calling ctx.LoadModule on a field whose tag only has inline_key, e.g. `caddy:"inline_key=handler"`, or is empty `caddy:""`.
Common situations: Authoring a custom Caddy module and forgetting the namespace in the tag; renaming the tag key (name_space, ns) while coding; tags for map fields where the author assumed the key is implied.
Related errors
- malformed tag on field %s: %v
- unable to determine module name without inline_key when type
- unable to determine module name without inline_key because t
- 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/24eb36fae3dea310.
Report an issue: GitHub.