musistudio/claude-code-router · error · Error
Cloudflare Pages publishing requires a runtime with fetch, F
Error message
Cloudflare Pages publishing requires a runtime with fetch, FormData, and Blob support.
What it means
Guard error thrown before attempting a Cloudflare Pages direct-upload deployment because the current JavaScript runtime lacks FormData or Blob constructors. The deployment flow builds a multipart form with FormData/Blob, which requires a modern browser-like or Node 18+ runtime.
Source
Thrown at packages/electron/bundled-plugins/claude-design/index.cjs:5635
headers: {
"content-type": "application/json"
},
method: "POST"
});
return { filesCached: 0, filesUploaded: files.length, skipped: false };
}
function cloudflarePagesUploadToken(payload) {
if (isRecord(payload?.result)) {
return stringValue(payload.result.jwt) || stringValue(payload.result.token) || stringValue(payload.result.value);
}
return stringValue(payload?.result) || stringValue(payload?.jwt) || stringValue(payload?.token);
}
async function createCloudflarePagesDeployment(config, projectName, files, session, body) {
if (typeof FormData !== "function" || typeof Blob !== "function") {
throw new Error("Cloudflare Pages publishing requires a runtime with fetch, FormData, and Blob support.");
}
const branch = stringValue(body?.branch) || stringValue(body?.git_branch) || config.branch || "main";
const commitSha = claudeShipDeploymentCommitSha(files);
const form = new FormData();
form.set("branch", branch);
form.set("commit_dirty", "false");
form.set("commit_hash", commitSha);
form.set("commit_message", `Publish ${session.title || session.id} from Claude Ship`);
form.set("pages_build_output_dir", ".");
form.set("manifest", JSON.stringify(Object.fromEntries(files.map((file) => [file.path, file.hash]))));
for (const file of files) {
form.set(file.hash, new Blob([file.body], { type: file.contentType }), file.path);
if (file.path.startsWith("_")) {
form.set(file.path, new Blob([file.body], { type: file.contentType }), file.path);
}
}
const accountId = encodeURIComponent(config.accountId);View on GitHub (pinned to 99f24806c6)
Solutions
- Run in Node 18+ or a browser/Electron renderer context where FormData and Blob are global
- If in Node <18, import undici's FormData/Blob and assign them to globals before calling
- Upgrade the Electron/host app so the runtime provides fetch/FormData/Blob
- Add a runtime capability check with a clear message at startup instead of at publish time
Example fix
// before
// Node 16: FormData undefined -> throws
await createCloudflarePagesDeployment(config, name, files, session, body);
// after
import { FormData, Blob } from 'undici';
globalThis.FormData ??= FormData;
globalThis.Blob ??= Blob;
await createCloudflarePagesDeployment(config, name, files, session, body); Defensive patterns
Strategy: type-guard
Validate before calling
const canDeploy = typeof fetch === 'function' && typeof FormData === 'function' && typeof Blob === 'function';
if (!canDeploy) await import('undici').then(u => Object.assign(globalThis, { FormData: u.FormData, Blob: u.Blob })); Type guard
function supportsDirectUpload(): boolean {
return typeof fetch === 'function' && typeof FormData === 'function' && typeof Blob === 'function';
} Try / catch
catch (e) { if (e.message.includes('fetch, FormData, and Blob')) { polyfill or upgrade runtime, then retry once } else throw e; } Prevention
- Pin engines: node >=18 in package.json
- Add a startup capability assertion in hosts bundling the connector
- Polyfill undici FormData/Blob in test environments
When it happens
Trigger: Running createCloudflarePagesDeployment in Node <18, a restricted sandbox/renderer without FormData, or a polyfill-free environment where typeof FormData !== 'function'.
Common situations: Bundling the connector for an older Electron/Node runtime, running in a worker where FormData is not global, or a bundler stripping/stubbing browser globals.
Related errors
- ${productName} is only available in CCR Desktop.
- ${productName} runtime module was not found. Rebuild app ass
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/c5a0a329dfdafe7d.
Report an issue: GitHub.