{"record":{"id":"c5a0a329dfdafe7d","repo":"musistudio/claude-code-router","slug":"cloudflare-pages-publishing-requires-a-runtime-wit","errorCode":null,"errorMessage":"Cloudflare Pages publishing requires a runtime with fetch, FormData, and Blob support.","messagePattern":"Cloudflare Pages publishing requires a runtime with fetch, FormData, and Blob support\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/electron/bundled-plugins/claude-design/index.cjs","lineNumber":5635,"sourceCode":"    headers: {\n      \"content-type\": \"application/json\"\n    },\n    method: \"POST\"\n  });\n\n  return { filesCached: 0, filesUploaded: files.length, skipped: false };\n}\n\nfunction cloudflarePagesUploadToken(payload) {\n  if (isRecord(payload?.result)) {\n    return stringValue(payload.result.jwt) || stringValue(payload.result.token) || stringValue(payload.result.value);\n  }\n  return stringValue(payload?.result) || stringValue(payload?.jwt) || stringValue(payload?.token);\n}\n\nasync function createCloudflarePagesDeployment(config, projectName, files, session, body) {\n  if (typeof FormData !== \"function\" || typeof Blob !== \"function\") {\n    throw new Error(\"Cloudflare Pages publishing requires a runtime with fetch, FormData, and Blob support.\");\n  }\n  const branch = stringValue(body?.branch) || stringValue(body?.git_branch) || config.branch || \"main\";\n  const commitSha = claudeShipDeploymentCommitSha(files);\n  const form = new FormData();\n  form.set(\"branch\", branch);\n  form.set(\"commit_dirty\", \"false\");\n  form.set(\"commit_hash\", commitSha);\n  form.set(\"commit_message\", `Publish ${session.title || session.id} from Claude Ship`);\n  form.set(\"pages_build_output_dir\", \".\");\n  form.set(\"manifest\", JSON.stringify(Object.fromEntries(files.map((file) => [file.path, file.hash]))));\n  for (const file of files) {\n    form.set(file.hash, new Blob([file.body], { type: file.contentType }), file.path);\n    if (file.path.startsWith(\"_\")) {\n      form.set(file.path, new Blob([file.body], { type: file.contentType }), file.path);\n    }\n  }\n\n  const accountId = encodeURIComponent(config.accountId);","sourceCodeStart":5617,"sourceCodeEnd":5653,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/electron/bundled-plugins/claude-design/index.cjs#L5617-L5653","documentation":"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.","triggerScenarios":"Running createCloudflarePagesDeployment in Node <18, a restricted sandbox/renderer without FormData, or a polyfill-free environment where typeof FormData !== 'function'.","commonSituations":"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.","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"],"exampleFix":"// before\n// Node 16: FormData undefined -> throws\nawait createCloudflarePagesDeployment(config, name, files, session, body);\n\n// after\nimport { FormData, Blob } from 'undici';\nglobalThis.FormData ??= FormData;\nglobalThis.Blob ??= Blob;\nawait createCloudflarePagesDeployment(config, name, files, session, body);","handlingStrategy":"type-guard","validationCode":"const canDeploy = typeof fetch === 'function' && typeof FormData === 'function' && typeof Blob === 'function';\nif (!canDeploy) await import('undici').then(u => Object.assign(globalThis, { FormData: u.FormData, Blob: u.Blob }));","typeGuard":"function supportsDirectUpload(): boolean {\n  return typeof fetch === 'function' && typeof FormData === 'function' && typeof Blob === 'function';\n}","tryCatchPattern":"catch (e) { if (e.message.includes('fetch, FormData, and Blob')) { polyfill or upgrade runtime, then retry once } else throw e; }","preventionTips":["Pin engines: node >=18 in package.json","Add a startup capability assertion in hosts bundling the connector","Polyfill undici FormData/Blob in test environments"],"tags":["cloudflare-pages","runtime","formdata","compatibility"],"backgroundTag":"unsupported-runtime-api","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}