{"record":{"id":"941397c8fc90f89d","repo":"nexu-io/open-design","slug":"cloudflare-pages-project-name-could-not-be-generat","errorCode":null,"errorMessage":"Cloudflare Pages project name could not be generated.","messagePattern":"Cloudflare Pages project name could not be generated\\.","errorType":"http","errorClass":"DeployError","httpStatus":400,"severity":"error","filePath":"apps/daemon/src/deploy.ts","lineNumber":619,"sourceCode":"    throw new DeployError('Cloudflare zone selection no longer matches the selected domain.', 400, {\n      errorCode: 'cloudflare_zone_mismatch',\n    });\n  }\n  if (zone?.status && zone.status !== 'active') {\n    throw new DeployError('Cloudflare custom domains require an active zone.', 400, {\n      errorCode: 'cloudflare_zone_inactive',\n    });\n  }\n  if (zone?.type && zone.type !== 'full') {\n    throw new DeployError('Cloudflare custom domains require a full DNS zone.', 400, {\n      errorCode: 'cloudflare_zone_not_full',\n    });\n  }\n  return { ...selection, zoneName };\n}\n\nasync function setupCloudflarePagesCustomDomain({ config, projectId, selection, pagesDevUrl, priorMetadata }: { config: DeployConfig; projectId: string; selection: CloudflarePagesDeploySelection; pagesDevUrl: string; priorMetadata?: JsonObject | undefined }) {\n  if (!config.projectName) throw new DeployError('Cloudflare Pages project name could not be generated.', 400);\n  const pagesTarget = normalizeHostname(hostnameFromUrl(pagesDevUrl) || `${config.projectName}.pages.dev`);\n  const marker = cloudflarePagesDnsMarker(projectId, config.projectName, pagesTarget);\n  const base = {\n    hostname: selection.hostname,\n    url: `https://${selection.hostname}`,\n    zoneId: selection.zoneId,\n    zoneName: selection.zoneName,\n    domainPrefix: selection.domainPrefix,\n  };\n\n  let dns;\n  try {\n    dns = await ensureCloudflarePagesCnameRecord({\n      config,\n      selection,\n      target: pagesTarget,\n      marker,\n      priorMetadata,","sourceCodeStart":601,"sourceCodeEnd":637,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/deploy.ts#L601-L637","documentation":"Thrown by setupCloudflarePagesCustomDomain in apps/daemon/src/deploy.ts:619 as `DeployError('Cloudflare Pages project name could not be generated.', 400)` when `config.projectName` is empty. The project name identifies the Pages project to bind the custom domain to (`<projectName>.pages.dev`) and to tag DNS records. Normally it is derived from the OD project upstream, so an empty value here indicates derivation failed upstream or the config object was constructed incompletely.","triggerScenarios":"Reaching setupCloudflarePagesCustomDomain with a `config` whose `projectName` is empty. Because deployToCloudflarePages also guards projectName (deploy.ts:481), reaching this point usually means the custom-domain setup was invoked directly or via a path that bypassed the deploy guard.","commonSituations":"The deploy route derives projectName from projectId but projectId was empty; a direct caller constructed a DeployConfig without setting projectName; a code path called setupCloudflarePagesCustomDomain independently of deployToCloudflarePages.","solutions":["Ensure projectName is derived and set on the config before invoking setupCloudflarePagesCustomDomain (the deploy route derives it like Vercel's `od-${projectId}`).","Route custom-domain setup through deployToCloudflarePages so the projectName guard at line 481 catches the problem earlier.","Pass a non-empty projectId so projectName derivation succeeds."],"exampleFix":"null","handlingStrategy":"validation","validationCode":"const projectName = deriveProjectName(projectId); // e.g. `od-${projectId}`\nif (!projectName) {\n  return res.status(400).json({ error: 'Could not derive a Cloudflare Pages project name.' });\n}\nconst config = { ...(await readCloudflarePagesConfig()), projectName };","typeGuard":"function hasProjectName(config: Partial<DeployConfig>): config is DeployConfig & { projectName: string } {\n  return typeof config.projectName === 'string' && config.projectName.length > 0;\n}","tryCatchPattern":"try {\n  await setupCloudflarePagesCustomDomain({ config, projectId, selection, pagesDevUrl, priorMetadata });\n} catch (err) {\n  if (err instanceof DeployError && /project name/i.test(err.message)) {\n    return res.status(400).json({ error: 'Project name missing; ensure projectId is set.' });\n  }\n  throw err;\n}","preventionTips":["Always derive projectName from projectId at the deploy route and set it on the config object before any custom-domain step.","Route custom-domain setup through deployToCloudflarePages so its earlier guard (line 481) catches a missing projectName.","Reject deploys with an empty projectId at the API boundary."],"tags":["deploy","cloudflare","validation","project-name","custom-domain"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}