caddyserver/caddy · error
module name not specified with key '%s' in %+v
Error message
module name not specified with key '%s' in %+v
What it means
Inline module maps in Caddy JSON (e.g. a handler object {"handler": "..."}, or matchers {"match": ...}) are decoded by getModuleNameInline, which unmarshals the object to a map and extracts the module-name key. If that key is absent, not a string, or empty, this error is returned showing the whole object.
Source
Thrown at modules.go:272
sort.Strings(names)
return names
}
// getModuleNameInline loads the string value from raw of moduleNameKey,
// where raw must be a JSON encoding of a map. It returns that value,
// along with the result of removing that key from raw.
func getModuleNameInline(moduleNameKey string, raw json.RawMessage) (string, json.RawMessage, error) {
var tmp map[string]any
err := json.Unmarshal(raw, &tmp)
if err != nil {
return "", nil, err
}
moduleName, ok := tmp[moduleNameKey].(string)
if !ok || moduleName == "" {
return "", nil, fmt.Errorf("module name not specified with key '%s' in %+v", moduleNameKey, tmp)
}
// remove key from the object, otherwise decoding it later
// will yield an error because the struct won't recognize it
// (this is only needed because we strictly enforce that
// all keys are recognized when loading modules)
delete(tmp, moduleNameKey)
result, err := json.Marshal(tmp)
if err != nil {
return "", nil, fmt.Errorf("re-encoding module configuration: %v", err)
}
return moduleName, result, nil
}
// Provisioner is implemented by modules which may need to perform
// some additional "setup" steps immediately after being loaded.
// Provisioning should be fast (imperceptible running time). IfView on GitHub (pinned to 50e54ee279)
Solutions
- Find the object printed in the error (%+v shows its keys) and add the missing name key — commonly "handler" inside route objects, "match" inside matchers, "wrapper" inside listener wrappers.
- Ensure the key's value is a non-empty JSON string.
- Prefer generating JSON with 'caddy adapt' from a Caddyfile so keys are always well-formed.
- Validate configs with 'caddy validate --config x.json --adapter json' before loading.
Example fix
// before (json)
{"route": [{"handle": [{"statuses": 404}]}]}
// after
{"route": [{"handle": [{"handler": "error", "status_code": 404}]}]} Defensive patterns
Strategy: validation
Validate before calling
// client-side check that every inline module object has its name key
func hasModuleKey(obj map[string]any, key string) error {
name, ok := obj[key].(string)
if !ok || name == "" {
return fmt.Errorf("object %v missing module name key %q", obj, key)
}
return nil
} Try / catch
if err := json.Unmarshal(cfgJSON, &cfg); err != nil {
if strings.Contains(err.Error(), "module name not specified") {
// the error prints the offending object — add the missing key (handler/match/wrapper)
}
return err
} Prevention
- Generate JSON via 'caddy adapt' instead of hand-writing.
- Add JSON-schema checks for route objects requiring a handler key.
- Run 'caddy validate --adapter json' in CI on every committed config.
When it happens
Trigger: A JSON config where an inline module object omits its discriminator key: a route handler without "handler", a listener wrapper without "wrapper", a matcher without "match" — or where the key's value is a number/null/empty string.
Common situations: Hand-written or templated JSON configs; JSON produced by converting Caddyfile output and then hand-stripping keys; API clients (caddy adapt/load over the admin endpoint) sending partially-built objects; version drift after a key rename.
Related errors
- invalid action type
- no identifiers configured
- unmarshaling admin listener address from config: %v
- config is not valid JSON: %w, at offset %d; did you mean to
- config is not valid JSON: %w; did you mean to use a config a
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/97839f21308659db.
Report an issue: GitHub.