{"record":{"id":"b9efcb6ef83780c9","repo":"goharbor/harbor","slug":"invalid-json-request","errorCode":null,"errorMessage":"invalid json request","messagePattern":"invalid json request","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"src/common/api/base.go","lineNumber":87,"sourceCode":"func (b *BaseAPI) Render() error {\n\treturn nil\n}\n\n// RenderError provides shortcut to render http error\nfunc (b *BaseAPI) RenderError(code int, text string) {\n\tlib_http.SendError(b.Ctx.ResponseWriter, &commonhttp.Error{\n\t\tCode:    code,\n\t\tMessage: text,\n\t})\n}\n\n// DecodeJSONReq decodes a json request\nfunc (b *BaseAPI) DecodeJSONReq(v any) error {\n\terr := json.Unmarshal(b.Ctx.Input.CopyBody(1<<35), v)\n\tif err != nil {\n\t\tlog.Errorf(\"Error while decoding the json request, error: %v, %v\",\n\t\t\terr, string(b.Ctx.Input.CopyBody(1 << 35)[:]))\n\t\treturn errors.New(\"invalid json request\")\n\t}\n\treturn nil\n}\n\n// Validate validates v if it implements interface validation.ValidFormer\nfunc (b *BaseAPI) Validate(v any) (bool, error) {\n\tvalidator := validation.Validation{}\n\tisValid, err := validator.Valid(v)\n\tif err != nil {\n\t\tlog.Errorf(\"failed to validate: %v\", err)\n\t\treturn false, err\n\t}\n\n\tif !isValid {\n\t\tvar message strings.Builder\n\t\tfor _, e := range validator.Errors {\n\t\t\tmessage.WriteString(fmt.Sprintf(\"%s %s \\n\", e.Field, e.Message))\n\t\t}","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/src/common/api/base.go#L69-L105","documentation":"DecodeJSONReq is the shared decoder for every JSON request body handled by Harbor core API handlers. It runs json.Unmarshal on the copied body (up to 1<<35 bytes); on failure it logs the underlying json error plus the body prefix and returns a sanitized 'invalid json request' error so raw parse details never leak to the client.","triggerScenarios":"Any POST/PUT to a Harbor core API endpoint whose body fails json.Unmarshal for the target struct: syntax errors, trailing commas, single-quoted strings, wrong field types, truncated bodies, extra characters after the top-level JSON value, or a body that is not JSON at all.","commonSituations":"Hand-written curl with shell-quoting mistakes, clients sending form-encoded data while claiming Content-Type: application/json, proxies or CDNs truncating bodies, UTF-8 BOM prefixes, mismatched Content-Length.","solutions":["Validate the body client-side before sending: pipe through `jq .`, JSON.parse, or Go json.Valid","Compare against a known-good request with curl --data-binary @request.json","Check for proxy/gateway body truncation (Content-Length vs actual bytes) if the same client works locally","Inspect harbor-core logs — the error line contains the exact json.Unmarshal failure and a body prefix pinpointing the offending offset"],"exampleFix":"# before (shell quoting mangles the JSON)\ncurl -X POST -H 'Content-Type: application/json' -d \"{name: \\\"proj\\\"}\" https://harbor/api/v2.0/projects\n# after\ncurl -X POST -H 'Content-Type: application/json' -d '{\"name\":\"proj\"}' https://harbor/api/v2.0/projects","handlingStrategy":"validation","validationCode":"// client-side, before sending\nif !json.Valid(body) {\n    return fmt.Errorf(\"refusing to send invalid JSON: %s\", body)\n}\nreq, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(body))\nreq.Header.Set(\"Content-Type\", \"application/json\")","typeGuard":null,"tryCatchPattern":"if err := api.DecodeJSONReq(v); err != nil {\n    if strings.Contains(err.Error(), \"invalid json request\") {\n        // body-level JSON problem: log and reject the request, do not retry unchanged\n    }\n}","preventionTips":["Build request bodies by marshaling a typed struct instead of string concatenation","Pipe manual curl payloads through jq . first","Check harbor-core logs for the embedded json.Unmarshal offset when debugging"],"tags":["go","harbor","api","json","validation"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}