caddyserver/caddy · error
position %d: %v
Error message
position %d: %v
What it means
Caddy's module loader (Context.LoadModule) uses reflection to provision struct fields typed as []json.RawMessage, where each slice element is an inline module (module name embedded as a key in the JSON object). When loading the element at index i fails, this error decorates the underlying failure with the slice position. The underlying cause is almost always an unknown module name, a malformed inline module object, or a provisioning/decoding failure inside the nested module.
Source
Thrown at context.go:233
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++ {
innerVal := val.Index(i)
var allInner []any
for j := 0; j < innerVal.Len(); j++ {
innerInnerVal, err := ctx.loadModuleInline(inlineModuleKey, moduleNamespace, innerVal.Index(j).Interface().(json.RawMessage))
if err != nil {
return nil, fmt.Errorf("position %d: %v", j, err)View on GitHub (pinned to 50e54ee279)
Solutions
- Read the %v part of the message: it names the real cause (e.g. 'unknown module: http.handlers.fwo' or 'decoding module config: ...')
- Check the JSON array element at the reported 0-based position; verify its inline module-name key (handler/matcher/listener/etc.) is present and spelled correctly
- Verify the module is registered in this build: run `caddy list-modules` and confirm the module ID appears (add the plugin via xcaddy build or an import if missing)
- Remove unrecognized fields from that element or fix field types, since Caddy uses strict JSON decoding (unknown keys are rejected)
Example fix
// before (JSON config)
"routes": [ { "handle": [ { "handlr": "static_response", "body": "hi" } ] } ]
// after
"routes": [ { "handle": [ { "handler": "static_response", "body": "hi" } ] } ] Defensive patterns
Strategy: validation
Validate before calling
// Before applying config: adapt + validate so positions/inline keys are checked upfront
cmd := exec.Command("caddy", "validate", "--config", "Caddyfile", "--adapter", "caddyfile")
if out, err := cmd.CombinedOutput(); err != nil {
log.Fatalf("config invalid: %v\n%s", err, out)
} Try / catch
// In Go code embedding Caddy
if _, err := ctx.LoadModule(field, raw); err != nil {
return fmt.Errorf("loading inline module slice: %w", err) // 'position N:' names the element
} Prevention
- Validate configs with `caddy validate` before deploying or reloading
- Generate JSON via `caddy adapt` instead of hand-writing inline module objects
- Verify every module ID exists with `caddy list-modules` before referencing it
When it happens
Trigger: A module struct has a field like []json.RawMessage with caddy:"module=..." tags; the JSON config supplies an array of inline module objects; ctx.loadModuleInline fails for element i (e.g. missing inline module-name key, unregistered module name, or StrictUnmarshalJSON rejecting a field), and LoadModule returns fmt.Errorf("position %d: %v", i, err).
Common situations: Typing a wrong handler/module name in a JSON array of matchers or handlers; forgetting the inline key (e.g. "handler" or "matcher") in one element of the array; using a plugin module in JSON config without building a Caddy binary that imports the plugin; strict decoding rejecting an unknown field in one element.
Related errors
- key %s: %v
- decoding module config: %s: %v
- loading module '%s': %v
- decoding request body: %w, at offset %d
- decoding request body: %w
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/988a518708da8c24.
Report an issue: GitHub.