{"record":{"id":"d249837d22925fcc","repo":"caddyserver/caddy","slug":"decoding-request-body-w-at-offset-d","errorCode":null,"errorMessage":"decoding request body: %w, at offset %d","messagePattern":"decoding request body: %w, at offset (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"admin.go","lineNumber":1170,"sourceCode":"\n// unsyncedConfigAccess traverses into the current config and performs\n// the operation at path according to method, using body and out as\n// needed. This is a low-level, unsynchronized function; most callers\n// will want to use changeConfig or readConfig instead. This requires a\n// read or write lock on currentCtxMu, depending on method (GET needs\n// only a read lock; all others need a write lock).\nfunc unsyncedConfigAccess(method, path string, body []byte, out io.Writer) error {\n\tvar err error\n\tvar val any\n\n\t// if there is a request body, decode it into the\n\t// variable that will be set in the config according\n\t// to method and path\n\tif len(body) > 0 {\n\t\terr = json.Unmarshal(body, &val)\n\t\tif err != nil {\n\t\t\tif jsonErr, ok := err.(*json.SyntaxError); ok {\n\t\t\t\treturn fmt.Errorf(\"decoding request body: %w, at offset %d\", jsonErr, jsonErr.Offset)\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"decoding request body: %w\", err)\n\t\t}\n\t}\n\n\tenc := json.NewEncoder(out)\n\n\tcleanPath := strings.Trim(path, \"/\")\n\tif cleanPath == \"\" {\n\t\treturn fmt.Errorf(\"no traversable path\")\n\t}\n\n\tparts := strings.Split(cleanPath, \"/\")\n\tif len(parts) == 0 {\n\t\treturn fmt.Errorf(\"path missing\")\n\t}\n\n\t// A path that ends with \"...\" implies:","sourceCodeStart":1152,"sourceCodeEnd":1188,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/admin.go#L1152-L1188","documentation":"Returned by unsyncedConfigAccess when the JSON request body cannot be unmarshaled and the failure is a *json.SyntaxError. The error includes the byte offset where JSON parsing failed, e.g. 'decoding request body: invalid character '\\'' looking for beginning of value, at offset 2'. This is a malformed-JSON-body problem, not a schema problem.","triggerScenarios":"POST/PUT/PATCH to /config/... with syntactically broken JSON: trailing commas, single quotes, unescaped newlines in strings, wrong content-type encoding, or a truncated body cut off by a proxy.","commonSituations":"Hand-written curl payloads with shell quoting mistakes; JSON produced by string concatenation instead of a serializer; request bodies truncated by a reverse proxy or client timeout; comments in JSON (JSON5 style) which Go's decoder rejects.","solutions":["Validate the exact bytes you send with a JSON linter or jq: echo \"$BODY\" | jq .","Use a real JSON serializer in your script/client instead of string concatenation","Use a heredoc with quoted delimiter in curl so the shell does not mangle quotes: curl -X POST --data @- http://localhost:2019/config/apps/http/servers <<'EOF' ... EOF","Check the reported offset against your payload to find the exact broken byte"],"exampleFix":"# before\ncurl -X POST http://localhost:2019/config/apps/http/servers/myserver/routes \\\n  -d \"{ listen: [':8080'] ,}\"   # invalid JSON\n# after\ncurl -X POST http://localhost:2019/config/apps/http/servers/myserver/routes \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"listen\":[\":8080\"]}'","handlingStrategy":"validation","validationCode":"import json\ndef safe_config_call(body: str):\n    json.loads(body)  # raises locally with a clear error before touching Caddy\n    return body","typeGuard":null,"tryCatchPattern":"Catch locally first: json.loads()/jq validation before send; on 400 from Caddy, parse the offset from 'at offset N' and point at byte N of your payload.","preventionTips":["Always serialize JSON with a library, never string concatenation","In curl heredocs use <<'EOF' (quoted) to stop shell quote mangling"],"tags":["caddy","admin-api","json","bad-request","config"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}