{"record":{"id":"97839f21308659db","repo":"caddyserver/caddy","slug":"module-name-not-specified-with-key-s-in-v","errorCode":null,"errorMessage":"module name not specified with key '%s' in %+v","messagePattern":"module name not specified with key '(.+?)' in %\\+v","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules.go","lineNumber":272,"sourceCode":"\n\tsort.Strings(names)\n\n\treturn names\n}\n\n// getModuleNameInline loads the string value from raw of moduleNameKey,\n// where raw must be a JSON encoding of a map. It returns that value,\n// along with the result of removing that key from raw.\nfunc getModuleNameInline(moduleNameKey string, raw json.RawMessage) (string, json.RawMessage, error) {\n\tvar tmp map[string]any\n\terr := json.Unmarshal(raw, &tmp)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\n\tmoduleName, ok := tmp[moduleNameKey].(string)\n\tif !ok || moduleName == \"\" {\n\t\treturn \"\", nil, fmt.Errorf(\"module name not specified with key '%s' in %+v\", moduleNameKey, tmp)\n\t}\n\n\t// remove key from the object, otherwise decoding it later\n\t// will yield an error because the struct won't recognize it\n\t// (this is only needed because we strictly enforce that\n\t// all keys are recognized when loading modules)\n\tdelete(tmp, moduleNameKey)\n\tresult, err := json.Marshal(tmp)\n\tif err != nil {\n\t\treturn \"\", nil, fmt.Errorf(\"re-encoding module configuration: %v\", err)\n\t}\n\n\treturn moduleName, result, nil\n}\n\n// Provisioner is implemented by modules which may need to perform\n// some additional \"setup\" steps immediately after being loaded.\n// Provisioning should be fast (imperceptible running time). If","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules.go#L254-L290","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (json)\n{\"route\": [{\"handle\": [{\"statuses\": 404}]}]}\n\n// after\n{\"route\": [{\"handle\": [{\"handler\": \"error\", \"status_code\": 404}]}]}","handlingStrategy":"validation","validationCode":"// client-side check that every inline module object has its name key\nfunc hasModuleKey(obj map[string]any, key string) error {\n    name, ok := obj[key].(string)\n    if !ok || name == \"\" {\n        return fmt.Errorf(\"object %v missing module name key %q\", obj, key)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := json.Unmarshal(cfgJSON, &cfg); err != nil {\n    if strings.Contains(err.Error(), \"module name not specified\") {\n        // the error prints the offending object — add the missing key (handler/match/wrapper)\n    }\n    return err\n}","preventionTips":["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."],"tags":["json","module-system","configuration","validation"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}