{"record":{"id":"895d54de14307835","repo":"vercel/ai","slug":"the-response-body-is-empty-895d54","errorCode":null,"errorMessage":"The response body is empty.","messagePattern":"The response body is empty\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/angular/src/lib/structured-object.ng.ts","lineNumber":167,"sourceCode":"      const response = await actualFetch(this.options.api, {\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/json',\n          ...normalizeHeaders(this.options.headers),\n        },\n        credentials: this.options.credentials,\n        signal: abortController.signal,\n        body: JSON.stringify(input),\n      });\n\n      if (!response.ok) {\n        throw new Error(\n          (await response.text()) ?? 'Failed to fetch the response.',\n        );\n      }\n\n      if (response.body == null) {\n        throw new Error('The response body is empty.');\n      }\n\n      let accumulatedText = '';\n      let latestObject: DeepPartial<RESULT> | undefined = undefined;\n\n      await response.body.pipeThrough(new TextDecoderStream()).pipeTo(\n        new WritableStream<string>({\n          write: async chunk => {\n            if (abortController?.signal.aborted) {\n              throw new DOMException('Stream aborted', 'AbortError');\n            }\n            accumulatedText += chunk;\n\n            const { value } = await parsePartialJson(accumulatedText);\n            const currentObject = value as DeepPartial<RESULT>;\n\n            if (!isDeepEqualData(latestObject, currentObject)) {\n              latestObject = currentObject;","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/angular/src/lib/structured-object.ng.ts#L149-L185","documentation":"After a successful (ok) HTTP response, StructuredObject streams the body. If `response.body` is null the library cannot stream and throws this error. It guards against servers that return 200 with no body.","triggerScenarios":"The fetch response is `ok` but `response.body == null` — typically a 204/no-content response or an environment (older browser/polyfill) where streaming response bodies are unsupported.","commonSituations":"Hitting an endpoint that returns an empty success response instead of a text stream; testing in a runtime without ReadableStream response bodies; misconfigured server route returning no content.","solutions":["Ensure the server endpoint actually streams the partial-JSON text response with a body.","Check the endpoint path/configuration — a wrong route may return an empty 200.","Test in a modern browser/runtime that supports `response.body` streaming (TextDecoderStream support too)."],"exampleFix":"// server: stream a body instead of returning empty 200\n// before\nres.statusCode = 200; res.end();\n// after\nres.statusCode = 200;\nres.write(JSON.stringify(partialObject)); res.end();","handlingStrategy":"validation","validationCode":"const res = await fetch(api, { method: 'GET' });\nif (!res.ok) throw new Error(`bad status ${res.status}`);\nconst hasBody = res.body != null;\nif (!hasBody) throw new Error('Endpoint returned no stream body');","typeGuard":"function hasStreamBody(r: Response): r is Response & { body: ReadableStream } { return r.body != null; }","tryCatchPattern":"try {\n  /* structured object flow */\n} catch (e) {\n  if (e instanceof Error && e.message === 'The response body is empty.') {\n    // server returned ok with no body; fix endpoint\n  }\n  throw e;\n}","preventionTips":["Ensure your endpoint streams a text body, never an empty 200/204.","Test in runtimes with ReadableStream response body support.","Add a smoke test asserting the endpoint produces a non-empty body."],"tags":["network","streaming","http","angular"],"backgroundTag":"empty-response-body","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}