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

  1. Read the %v part of the message: it names the real cause (e.g. 'unknown module: http.handlers.fwo' or 'decoding module config: ...')
  2. 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
  3. 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)
  4. 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

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


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/988a518708da8c24. Report an issue: GitHub.