vercel-labs/skills · error · Error
Download response has no body
Error message
Download response has no body
What it means
After a successful (2xx) response with an acceptable Content-Length, downloadToFile requires response.body to be present; a null body means the server declared success but provided no stream to read. In practice this happens with unusual server responses, broken proxies, or runtimes whose fetch implementation returns empty bodies for certain status/header combinations.
Source
Thrown at src/download-source.ts:105
redirect: 'follow',
});
if (!response.ok) {
throw new Error(`Download failed with HTTP ${response.status}`);
}
const contentLength = response.headers.get('content-length');
if (contentLength) {
const parsed = Number.parseInt(contentLength, 10);
if (Number.isFinite(parsed) && parsed > limits.downloadMaxBytes) {
throw new Error(
`Download is larger than ${limits.downloadMaxBytes} bytes. Set SKILLS_DOWNLOAD_MAX_BYTES to override.`
);
}
}
if (!response.body) {
throw new Error('Download response has no body');
}
let downloaded = 0;
const limitStream = new TransformStream<Uint8Array, Uint8Array>({
transform(chunk, controller) {
downloaded += chunk.byteLength;
if (downloaded > limits.downloadMaxBytes) {
throw new Error(
`Download is larger than ${limits.downloadMaxBytes} bytes. Set SKILLS_DOWNLOAD_MAX_BYTES to override.`
);
}
controller.enqueue(chunk);
},
});
await pipeline(response.body.pipeThrough(limitStream), createWriteStream(targetFile));
}
View on GitHub (pinned to 435076e789)
Solutions
- curl -v the URL and inspect whether a body is actually returned
- Retry — some proxies/CDNs intermittently return empty bodies
- If a custom fetch/mocked fetch is in play (tests), ensure the mock sets body
- Report to the server owner if the origin genuinely returns empty 200s
Example fix
# before skills add https://example.com/skills.zip # Download response has no body # after curl -v https://example.com/skills.zip -o skills.zip # inspect skills add ./skills.zip
Defensive patterns
Strategy: retry
Validate before calling
// Verify the endpoint returns a body before delegating
async function hasBody(url: string): Promise<boolean> {
const res = await fetch(url, { method: 'GET', headers: { Range: 'bytes=0-0' } });
return res.body != null;
} Type guard
null
Try / catch
try {
await downloadSource(url);
} catch (err) {
if (err instanceof Error && err.message === 'Download response has no body') {
await sleep(1000); // transient proxy behavior — retry once
return downloadSource(url);
}
throw err;
} Prevention
- Prefer static asset URLs over dynamic endpoints
- In tests, always set body on mocked fetch Responses
When it happens
Trigger: A 2xx response with a null/absent body — misbehaving CDNs, HEAD-like responses to GET, HTTP 204/304-style replies from redirects, or a fetch polyfill that doesn't populate body.
Common situations: Corporate proxies stripping bodies, server misconfiguration returning empty 200s, or unit tests with mocked fetch responses that omit the body field.
Related errors
- Download failed with HTTP ${response.status}
- Downloaded URL is empty
- Download is larger than ${limits.downloadMaxBytes} bytes. Se
- Archive contains unsafe path: ${entryPath}
- Downloaded URL is not a valid SKILL.md file or supported arc
AI-assisted analysis of vercel-labs/skills@435076e789 (2026-08-28).
Data as JSON: /api/errors/b0f47287913eb30a.
Report an issue: GitHub.