{"record":{"id":"3bf73739af1bdc7f","repo":"cayleygraph/cayley","slug":"request-data-is-too-large","errorCode":null,"errorMessage":"request data is too large","messagePattern":"request data is too large","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"server/http/api_v2.go","lineNumber":324,"sourceCode":"func (api *APIv2) ServeNodeDelete(w http.ResponseWriter, r *http.Request) {\n\tdefer r.Body.Close()\n\tif api.ro {\n\t\tjsonResponse(w, http.StatusForbidden, errors.New(\"database is read-only\"))\n\t\treturn\n\t}\n\tformat := getFormat(r, \"\", hdrContentType)\n\tif format == nil || format.UnmarshalValue == nil {\n\t\tjsonResponse(w, http.StatusBadRequest, fmt.Errorf(\"format is not supported for reading nodes\"))\n\t\treturn\n\t}\n\tconst limit = 128*1024 + 1\n\trd := io.LimitReader(r.Body, limit)\n\tdata, err := ioutil.ReadAll(rd)\n\tif err != nil {\n\t\tjsonResponse(w, http.StatusBadRequest, err)\n\t\treturn\n\t} else if len(data) == limit {\n\t\tjsonResponse(w, http.StatusBadRequest, fmt.Errorf(\"request data is too large\"))\n\t\treturn\n\t}\n\tv, err := format.UnmarshalValue(data)\n\tif err != nil {\n\t\tjsonResponse(w, http.StatusBadRequest, err)\n\t\treturn\n\t} else if v == nil {\n\t\tjsonResponse(w, http.StatusBadRequest, fmt.Errorf(\"cannot remove nil value\"))\n\t\treturn\n\t}\n\th, err := api.handleForRequest(r)\n\tif err != nil {\n\t\tjsonResponse(w, http.StatusBadRequest, err)\n\t\treturn\n\t}\n\terr = h.RemoveNode(v)\n\tif err != nil {\n\t\tjsonResponse(w, http.StatusInternalServerError, err)","sourceCodeStart":306,"sourceCodeEnd":342,"githubUrl":"https://github.com/cayleygraph/cayley/blob/81dcd7d73e45136bc0d01802a8ba4685d8a533eb/server/http/api_v2.go#L306-L342","documentation":"ServeNodeDelete reads the DELETE request body through an io.LimitReader capped at a configured limit. If the body fills that limit entirely (len(data) == limit), the payload is at or over the cap, so the API refuses it with a 400 rather than parsing an oversized value. This protects the server from unbounded bodies used to delete large values.","triggerScenarios":"Posting to /api/v2/node/delete with a request body whose serialized size equals or exceeds the server's configured max request size (the limit passed to io.LimitReader).","commonSituations":"Bulk-deletion scripts batching many nodes into one request; deployments started with a small max-request-size setting and later given larger workloads; clients accidentally inflating payloads (base64, duplicated entries).","solutions":["Split the delete payload into smaller batches so each request stays under the limit.","Increase the server's max request size configuration and restart Cayley.","Inspect the payload for accidental inflation (encoding, duplicates) with a smaller test request."],"exampleFix":"// before: one huge delete request\ncurl -X POST -d @all-nodes.json http://localhost:64210/api/v2/node/delete\n// after: split into batches\ncurl -X POST -d @nodes-batch-1.json http://localhost:64210/api/v2/node/delete\ncurl -X POST -d @nodes-batch-2.json http://localhost:64210/api/v2/node/delete","handlingStrategy":"validation","validationCode":"body, _ := json.Marshal(payload)\nserverLimit := 4 << 20 // must match the server's max request size\nif len(body) >= serverLimit {\n    return errors.New(\"delete payload exceeds server request-size limit; split into batches\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep client max body size below the server's configured request-size limit.","Split bulk deletes into batches well under the limit.","Check Content-Length before sending.","Log payload size when a 400 'request data is too large' is returned."],"tags":["http","request-size","cayley","api"],"backgroundTag":"payload-too-large","analyzedSha":"81dcd7d73e45136bc0d01802a8ba4685d8a533eb","analyzedAt":"2026-09-06T06:14:12.358Z","contentChangedAt":"2026-09-06T06:14:12.358Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}