{"record":{"id":"91309c858503a16e","repo":"caddyserver/caddy","slug":"w-at-offset-d","errorCode":null,"errorMessage":"%w, at offset %d","messagePattern":"%w, at offset (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules.go","lineNumber":347,"sourceCode":"\t\tbefore, after, isCut := strings.Cut(pair, \"=\")\n\t\tif !isCut {\n\t\t\treturn nil, fmt.Errorf(\"missing key in '%s' (pair %d)\", pair, i)\n\t\t}\n\t\tresults[before] = after\n\t}\n\treturn results, nil\n}\n\n// StrictUnmarshalJSON is like json.Unmarshal but returns an error\n// if any of the fields are unrecognized. Useful when decoding\n// module configurations, where you want to be more sure they're\n// correct.\nfunc StrictUnmarshalJSON(data []byte, v any) error {\n\tdec := json.NewDecoder(bytes.NewReader(data))\n\tdec.DisallowUnknownFields()\n\terr := dec.Decode(v)\n\tif jsonErr, ok := err.(*json.SyntaxError); ok {\n\t\treturn fmt.Errorf(\"%w, at offset %d\", jsonErr, jsonErr.Offset)\n\t}\n\treturn err\n}\n\nvar JSONRawMessageType = reflect.TypeFor[json.RawMessage]()\n\n// isJSONRawMessage returns true if the type is encoding/json.RawMessage.\nfunc isJSONRawMessage(typ reflect.Type) bool {\n\treturn typ == JSONRawMessageType\n}\n\n// isModuleMapType returns true if the type is map[string]json.RawMessage.\n// It assumes that the string key is the module name, but this is not\n// always the case. To know for sure, this function must return true, but\n// also the struct tag where this type appears must NOT define an inline_key\n// attribute, which would mean that the module names appear inline with the\n// values, not in the key.\nfunc isModuleMapType(typ reflect.Type) bool {","sourceCodeStart":329,"sourceCodeEnd":365,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules.go#L329-L365","documentation":"caddy.StrictUnmarshalJSON decodes module configuration with DisallowUnknownFields; when the JSON itself is syntactically malformed, the *json.SyntaxError is re-wrapped with its byte offset so you know exactly where parsing stopped. Unknown-field errors and type errors pass through unwrapped.","triggerScenarios":"Loading a config whose module JSON has a syntax error — trailing commas, unquoted keys, missing braces/brackets, stray characters — at the reported byte offset.","commonSituations":"Hand-edited JSON configs; heredocs or templating (envsubst, Helm) that mangle quotes/braces; concat of JSON fragments that leaves a dangling comma; files with a BOM or non-UTF-8 bytes.","solutions":["Open the file at the exact byte offset given in the error and fix the syntax there (remember offsets are 0-based bytes, and multi-byte UTF-8 characters shift column counts).","Run the file through a JSON linter or 'jq empty file.json' to locate all syntax errors.","Prefer the Caddyfile + 'caddy adapt' so syntax is machine-generated.","Check templating output (envsubst consuming braces is a classic) before loading."],"exampleFix":"// before (json)\n{\"apps\": {\"http\": {\"servers\": {\"srv0\": {\"listen\": [\":443\"],,}}}}\n\n// after\n{\"apps\": {\"http\": {\"servers\": {\"srv0\": {\"listen\": [\":443\"]}}}}","handlingStrategy":"validation","validationCode":"// pre-validate JSON syntax with offsets before loading\nfunc jsonOK(data []byte) error {\n    var v any\n    if err := json.Unmarshal(data, &v); err != nil {\n        if se, ok := err.(*json.SyntaxError); ok {\n            return fmt.Errorf(\"syntax error near offset %d: %w (context: %q)\", se.Offset, err, data[max(0, se.Offset-20):min(len(data), se.Offset+20)])\n        }\n        return err\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := caddy.Validate(cfg); err != nil {\n    var se *json.SyntaxError\n    if errors.As(err, &se) {\n        // jump to se.Offset in the file to fix the syntax\n    }\n    return err\n}","preventionTips":["Lint JSON in CI with jq or a JSON schema checker.","Quote heredoc delimiters ('EOF') to stop shell expansion of braces.","Avoid envsubst on raw JSON — substitute a template with unique tokens instead."],"tags":["json","parsing","configuration"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}