{"record":{"id":"422fd67a4e325c38","repo":"weaviate/weaviate","slug":"read-response-body-422fd6","errorCode":null,"errorMessage":"read response body","messagePattern":"read response body","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/ner-transformers/clients/ner.go","lineNumber":87,"sourceCode":"\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"marshal body\")\n\t}\n\n\treq, err := http.NewRequestWithContext(ctx, \"POST\", n.url(\"/ner/\"),\n\t\tbytes.NewReader(body))\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"create POST request\")\n\t}\n\n\tres, err := n.httpClient.Do(req)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"send POST request\")\n\t}\n\tdefer res.Body.Close()\n\n\tbodyBytes, err := io.ReadAll(res.Body)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"read response body\")\n\t}\n\n\tvar resBody nerResponse\n\tif err := json.Unmarshal(bodyBytes, &resBody); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse NER response (status %d): %w\", res.StatusCode, err)\n\t}\n\n\tif res.StatusCode > 399 {\n\t\treturn nil, errors.Errorf(\"fail with status %d: %s\", res.StatusCode, resBody.Error)\n\t}\n\n\tout := make([]ent.TokenResult, len(resBody.Tokens))\n\n\tfor i, elem := range resBody.Tokens {\n\t\tout[i].Certainty = elem.Certainty\n\t\tout[i].Distance = elem.Distance\n\t\tout[i].Entity = elem.Entity\n\t\tout[i].Word = elem.Word","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/weaviate/weaviate/blob/75aa4b6d11f8818305aafd4440b4e32794f7ca04/modules/ner-transformers/clients/ner.go#L69-L105","documentation":"Wrapping error from the ner-transformers client GetTokens when io.ReadAll fails to read the response body returned by the NER inference service, decorated as 'read response body'. This means the connection produced headers but the body stream broke mid-read — typically the inference container was killed/restarted (OOM or crash) or an intermediary severed the connection. The next statement also surfaces JSON parse problems with the HTTP status included, but this specific wrapper is the raw body-read I/O failure.","triggerScenarios":"GetTokens received an HTTP response but reading its body errored: inference container OOM-killed mid-response (common with long texts on memory-limited transformers), abrupt connection reset, keep-alive connection closed by a proxy, or a very large response truncated by an intermediary.","commonSituations":"Long input texts pushing the NER model past container memory limits so the pod is killed while streaming; Docker/Kubernetes restarting the inference container; a load balancer with a short idle/response timeout; flaky network between Weaviate and the module sidecar.","solutions":["Check the inner error ('unexpected EOF', 'connection reset by peer') and inspect inference container logs for OOM kills or restarts","Shorten or chunk the input text so the NER model fits within container memory limits","Raise the inference container memory limit (e.g. docker memory / k8s resources.limits) and enable swap-free headroom","Rule out intermediary timeouts: increase LB/proxy response timeouts or bypass the proxy for internal module traffic","Retry the request; if transient resets persist, pin a healthy inference image version and monitor container restarts"],"exampleFix":"// before (docker-compose)\nner-transformers:\n  image: semitechnologies/ner-transformers:latest\n# after\nner-transformers:\n  image: semitechnologies/ner-transformers:latest\n  mem_limit: 4g  # prevent OOM kill mid-response","handlingStrategy":"retry","validationCode":"// Keep inputs within safe size and confirm container headroom before large NER jobs\nif len(text) > maxSafeChars {\n\ttext = truncate(text, maxSafeChars)\n}\n// and: docker stats / kubectl top pod to verify inference container is not near its memory limit","typeGuard":"// Distinguish body-read breakage from parse errors so retries target the right cause\nfunc isBodyReadError(err error) bool {\n\tmsg := err.Error()\n\treturn strings.Contains(msg, \"read response body\") ||\n\t\tstrings.Contains(msg, \"unexpected EOF\") ||\n\t\tstrings.Contains(msg, \"connection reset\")\n}","tryCatchPattern":"tokens, err := nerClient.GetTokens(ctx, text)\nif err != nil && strings.Contains(err.Error(), \"read response body\") {\n\t// transient stream break: retry with backoff; if persistent, check inference container for OOM kills\n}","preventionTips":["Right-size inference container memory and truncate very long texts","Watch for OOM-killed / restarting inference pods (docker inspect, kubectl describe)","Avoid aggressive LB/proxy response timeouts on internal module traffic","Retry idempotent NER reads with capped exponential backoff","Pin a stable inference image version to rule out flaky builds"],"tags":["weaviate","ner-transformers","network","io","oom"],"backgroundTag":"connection-reset","analyzedSha":"75aa4b6d11f8818305aafd4440b4e32794f7ca04","analyzedAt":"2026-09-04T14:58:20.392Z","contentChangedAt":"2026-09-04T14:58:20.392Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}