{"record":{"id":"4d140c7911fe0311","repo":"twentyhq/twenty","slug":"download-returned-no-body","errorCode":null,"errorMessage":"download returned no body","messagePattern":"download returned no body","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/twenty-apps/public/call-recorder/src/logic-functions/flows/import-call-recording-media.util.ts","lineNumber":231,"sourceCode":"      fileName,\n      body: response.body,\n    });\n\n    throw new Error('download response is missing content-length');\n  }\n\n  if (contentLengthBytes > maxMediaFileSizeBytes) {\n    await cancelMediaDownloadBody({\n      callRecordingId,\n      fileName,\n      body: response.body,\n    });\n\n    return { outcome: 'too-large', sizeBytes: contentLengthBytes };\n  }\n\n  if (isNull(response.body)) {\n    throw new Error('download returned no body');\n  }\n\n  return {\n    outcome: 'opened',\n    body: response.body,\n    sizeBytes: contentLengthBytes,\n  };\n};\n\nconst uploadMediaStreamToStorage = async ({\n  callRecordingId,\n  metadataClient,\n  fileName,\n  fieldMetadataUniversalIdentifier,\n  body,\n  sizeBytes,\n}: {\n  callRecordingId: string;","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/twentyhq/twenty/blob/1f5dd2bbd2a8da3419c8cfd52dd545c0024df1a6/packages/twenty-apps/public/call-recorder/src/logic-functions/flows/import-call-recording-media.util.ts#L213-L249","documentation":"After the content-length checks pass, the downloader asserts `response.body` is a non-null `ReadableStream`. A null body means the fetch runtime did not provide a stream to read from, so there is nothing to upload; the code throws rather than proceed. This is distinct from a missing content-length (26) or a non-ok status (25).","triggerScenarios":"The fetch implementation in use does not expose streaming bodies (some runtimes/polyfills return `body: null`), the response was already consumed/cancelled upstream, or the media host returned a 2xx with an empty body that the runtime represents as null.","commonSituations":"Running the logic function in a runtime whose `fetch` does not implement streaming bodies; a polyfill mismatch; or a logic-function platform update that changed how response bodies are exposed.","solutions":["Confirm the runtime/polyfill providing `fetch` supports `ReadableStream` bodies (Node 18+ undici does; older polyfills may not).","Ensure nothing consumes `response.body` (e.g. a logging hook calling `.json()`/`.text()`) before this point.","If the host genuinely returns empty bodies for some artifacts, guard earlier and mark that artifact as unavailable instead of throwing.","Log `response.headers` and status alongside the null-body check to distinguish a host issue from a runtime issue."],"exampleFix":"// before\nif (isNull(response.body)) {\n  throw new Error('download returned no body');\n}\n\n// after — distinguish runtime-missing-stream from host-empty-body\nif (isNull(response.body)) {\n  throw new Error(\n    `download returned no body for ${fileName} (status=${response.status}, contentLength=${contentLengthBytes}); fetch runtime may not expose ReadableStream bodies`,\n  );\n}","handlingStrategy":"type-guard","validationCode":"// Confirm the runtime exposes a streaming fetch body before importing media.\nif (typeof Response === 'undefined' || typeof ReadableStream === 'undefined') {\n  throw new Error('Runtime does not support streaming response bodies; cannot import media');\n}","typeGuard":"const hasStreamingBody = (res: Response): res is Response & { body: ReadableStream<Uint8Array> } =>\n  !isNull(res.body) && typeof (res.body as ReadableStream<Uint8Array>).getReader === 'function';","tryCatchPattern":null,"preventionTips":["Run the media-import logic function in a runtime with native streaming fetch (Node 18+ undici).","Do not consume `response.body` (e.g. via `.json()`/`.text()`) in logging hooks before the download path reads it.","Log status + headers at the null-body check to distinguish host-empty-body from runtime-no-stream.","Pin the runtime version so a regression in fetch body support is caught immediately."],"tags":["network","recall","call-recorder","media-download","runtime"],"backgroundTag":null,"analyzedSha":"1f5dd2bbd2a8da3419c8cfd52dd545c0024df1a6","analyzedAt":"2026-08-12T15:37:27.593Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}