twentyhq/twenty · error · Error

download response is missing content-length

Error message

download response is missing content-length

What it means

The media-download flow requires a `Content-Length` header so it can pre-check the file size against `maxMediaFileSizeBytes` before streaming bytes. `parseContentLengthBytes` returns `undefined` when the header is missing or non-numeric; the code then cancels the response body and throws. Recall/media hosts that use chunked transfer encoding without a content-length therefore cannot be safely size-checked and are rejected.

Source

Thrown at packages/twenty-apps/public/call-recorder/src/logic-functions/flows/import-call-recording-media.util.ts:217

  if (!response.ok) {
    await cancelMediaDownloadBody({
      callRecordingId,
      fileName,
      body: response.body,
    });

    throw new Error(`download failed with status ${response.status}`);
  }

  if (isUndefined(contentLengthBytes)) {
    await cancelMediaDownloadBody({
      callRecordingId,
      fileName,
      body: response.body,
    });

    throw new Error('download response is missing content-length');
  }

  if (contentLengthBytes > maxMediaFileSizeBytes) {
    await cancelMediaDownloadBody({
      callRecordingId,
      fileName,
      body: response.body,
    });

    return { outcome: 'too-large', sizeBytes: contentLengthBytes };
  }

  if (isNull(response.body)) {
    throw new Error('download returned no body');
  }

  return {
    outcome: 'opened',

View on GitHub (pinned to 1f5dd2bbd2)

Solutions

  1. Confirm with Recall.ai / the media host whether `Content-Length` is guaranteed; if they switched to chunked encoding, the downloader must be rewritten to size-check by streaming and accumulating byte counts up to the cap.
  2. Check for an intermediary (corporate proxy, egress gateway) stripping the header and bypass it for the Recall media host.
  3. If the artifact is still being transcoded, wait for Recall to report the recording fully ready before importing media.
  4. As a defensive change, fall back to streaming with a running byte counter and abort at `maxMediaFileSizeBytes` when content-length is absent.

Example fix

// before
if (isUndefined(contentLengthBytes)) {
  await cancelMediaDownloadBody({ callRecordingId, fileName, body: response.body });
  throw new Error('download response is missing content-length');
}

// after — when content-length is absent, stream with an enforced cap
if (isUndefined(contentLengthBytes)) {
  if (isNull(response.body)) {
    throw new Error('download returned no body and no content-length');
  }
  return {
    outcome: 'opened',
    body: wrapStreamWithByteCap(response.body, maxMediaFileSizeBytes, callRecordingId, fileName),
    sizeBytes: 0,
  };
}
Defensive patterns

Strategy: validation

Validate before calling

const contentLengthBytes = parseContentLengthBytes(response.headers.get('content-length'));
if (isUndefined(contentLengthBytes)) {
  // Option A: reject early with a clear message;
  // Option B: stream with a running byte cap (see typeGuard/preventionTips).
  await cancelMediaDownloadBody({ callRecordingId, fileName, body: response.body });
  throw new Error(`download response for ${fileName} is missing content-length`);
}

Type guard

const hasUsableContentLength = (res: Response): boolean => {
  const v = res.headers.get('content-length');
  const n = v == null ? NaN : Number(v.trim());
  return Number.isFinite(n) && n >= 0;
};

Prevention

When it happens

Trigger: The media host responds with `Transfer-Encoding: chunked` and no `Content-Length`, the header is empty/malformed, or an intermediary (CDN/proxy) strips it. Any of these makes `contentLengthBytes` undefined after parsing.

Common situations: Recall changes its media CDN to chunked encoding; a proxy in front of the runtime strips content-length; downloading an artifact still being finalized so the size is unknown.

Related errors


AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12). Data as JSON: /api/errors/ef205940f9a09c49. Report an issue: GitHub.