{"record":{"id":"19a149e557a609b1","repo":"nexu-io/open-design","slug":"cloudflare-account-id-is-required","errorCode":null,"errorMessage":"Cloudflare account ID is required.","messagePattern":"Cloudflare account ID is required\\.","errorType":"http","errorClass":"DeployError","httpStatus":400,"severity":"error","filePath":"apps/daemon/src/deploy.ts","lineNumber":480,"sourceCode":"        status: typeof zone?.status === 'string' ? zone.status : undefined,\n        type: typeof zone?.type === 'string' ? zone.type : undefined,\n      }))\n      .filter((zone) => zone.id && zone.name),\n    cloudflarePages: normalizeCloudflarePagesConfigHints(config?.cloudflarePages),\n  };\n}\n\nexport async function deployToCloudflarePages(input: { config: DeployConfig; files: DeployFile[]; projectId?: string; cloudflarePages?: unknown; priorMetadata?: JsonObject | undefined; target?: 'preview' | 'production' }) {\n  const {\n    config,\n    files,\n    projectId = '',\n    cloudflarePages = undefined,\n    priorMetadata = undefined,\n    target = 'production',\n  } = input || {};\n  if (!config?.token) throw new DeployError('Cloudflare API token is required.', 400);\n  if (!config?.accountId) throw new DeployError('Cloudflare account ID is required.', 400);\n  if (!config?.projectName) throw new DeployError('Cloudflare Pages project name could not be generated.', 400);\n\n  const customDomainSelection = await validateCloudflarePagesDeploySelection(\n    config,\n    normalizeCloudflarePagesDeploySelection(cloudflarePages),\n  );\n\n  await ensureCloudflarePagesProject(config);\n\n  const uploadToken = await getCloudflarePagesUploadToken(config);\n  await uploadCloudflarePagesAssets(uploadToken, files);\n\n  const form = new FormData();\n  const manifest: Record<string, string> = {};\n  for (const file of files) {\n    manifest[`/${file.file}`] = cloudflarePagesAssetHash(file);\n  }\n  form.append('manifest', JSON.stringify(manifest));","sourceCodeStart":462,"sourceCodeEnd":498,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/deploy.ts#L462-L498","documentation":"Thrown by deployToCloudflarePages in apps/daemon/src/deploy.ts:480 as `DeployError('Cloudflare account ID is required.', 400)` — the second guard, immediately after the token check. The Cloudflare Pages API scopes project/asset/custom-domain operations under an account id (`account.id`), so a token alone is insufficient. Even if the token is valid, the deploy cannot proceed without the account ID.","triggerScenarios":"Calling `deployToCloudflarePages({ config, ... })` where `config.token` is non-empty but `config.accountId` is empty. Typically the user saved only a token (or the token field) and left the account ID blank.","commonSituations":"Config write persisted token but not accountId; user pasted the token into the wrong field; account ID field omitted in the UI form; accountId trimmed to empty due to whitespace-only input.","solutions":["Save the Cloudflare account ID alongside the token via writeCloudflarePagesConfig({ token, accountId }).","Find the account ID in the Cloudflare dashboard sidebar (right side on most pages) or via `GET /accounts` with the token.","Gate the deploy on both token and accountId being non-empty before calling deployToCloudflarePages."],"exampleFix":"// before\nawait deployToCloudflarePages({ config: { token: '...', accountId: '' }, files, projectId });\n\n// after\nawait writeCloudflarePagesConfig({ token: '...', accountId: 'abc123' });\nconst config = await readCloudflarePagesConfig();\nawait deployToCloudflarePages({ config, files, projectId });","handlingStrategy":"validation","validationCode":"const config = await readCloudflarePagesConfig();\nif (!config.token) return res.status(400).json({ error: 'Token required.' });\nif (!config.accountId) return res.status(400).json({ error: 'Account ID required.' });\nawait deployToCloudflarePages({ config, files, projectId });","typeGuard":"function hasCloudflareAccount(config: Partial<DeployConfig>): config is DeployConfig & { accountId: string } {\n  return typeof config.accountId === 'string' && config.accountId.trim().length > 0;\n}","tryCatchPattern":"try {\n  await deployToCloudflarePages({ config, files, projectId });\n} catch (err) {\n  if (err instanceof DeployError && err.status === 400 && /account ID/i.test(err.message)) {\n    return res.status(400).json({ error: 'Enter your Cloudflare account ID.' });\n  }\n  throw err;\n}","preventionTips":["Always persist accountId together with the token in one writeCloudflarePagesConfig call.","Make both token and accountId fields required in the credentials form.","Resolve accountId via GET /accounts if the user only knows the account name."],"tags":["deploy","cloudflare","validation","account-id"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}