nexu-io/open-design · error · DeployError

Cloudflare Pages project name could not be generated.

Error message

Cloudflare Pages project name could not be generated.

What it means

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.

Source

Thrown at apps/daemon/src/deploy.ts:619

    throw new DeployError('Cloudflare zone selection no longer matches the selected domain.', 400, {
      errorCode: 'cloudflare_zone_mismatch',
    });
  }
  if (zone?.status && zone.status !== 'active') {
    throw new DeployError('Cloudflare custom domains require an active zone.', 400, {
      errorCode: 'cloudflare_zone_inactive',
    });
  }
  if (zone?.type && zone.type !== 'full') {
    throw new DeployError('Cloudflare custom domains require a full DNS zone.', 400, {
      errorCode: 'cloudflare_zone_not_full',
    });
  }
  return { ...selection, zoneName };
}

async function setupCloudflarePagesCustomDomain({ config, projectId, selection, pagesDevUrl, priorMetadata }: { config: DeployConfig; projectId: string; selection: CloudflarePagesDeploySelection; pagesDevUrl: string; priorMetadata?: JsonObject | undefined }) {
  if (!config.projectName) throw new DeployError('Cloudflare Pages project name could not be generated.', 400);
  const pagesTarget = normalizeHostname(hostnameFromUrl(pagesDevUrl) || `${config.projectName}.pages.dev`);
  const marker = cloudflarePagesDnsMarker(projectId, config.projectName, pagesTarget);
  const base = {
    hostname: selection.hostname,
    url: `https://${selection.hostname}`,
    zoneId: selection.zoneId,
    zoneName: selection.zoneName,
    domainPrefix: selection.domainPrefix,
  };

  let dns;
  try {
    dns = await ensureCloudflarePagesCnameRecord({
      config,
      selection,
      target: pagesTarget,
      marker,
      priorMetadata,

View on GitHub (pinned to 5be4028344)

Solutions

  1. Ensure projectName is derived and set on the config before invoking setupCloudflarePagesCustomDomain (the deploy route derives it like Vercel's `od-${projectId}`).
  2. Route custom-domain setup through deployToCloudflarePages so the projectName guard at line 481 catches the problem earlier.
  3. Pass a non-empty projectId so projectName derivation succeeds.

Example fix

null
Defensive patterns

Strategy: validation

Validate before calling

const projectName = deriveProjectName(projectId); // e.g. `od-${projectId}`
if (!projectName) {
  return res.status(400).json({ error: 'Could not derive a Cloudflare Pages project name.' });
}
const config = { ...(await readCloudflarePagesConfig()), projectName };

Type guard

function hasProjectName(config: Partial<DeployConfig>): config is DeployConfig & { projectName: string } {
  return typeof config.projectName === 'string' && config.projectName.length > 0;
}

Try / catch

try {
  await setupCloudflarePagesCustomDomain({ config, projectId, selection, pagesDevUrl, priorMetadata });
} catch (err) {
  if (err instanceof DeployError && /project name/i.test(err.message)) {
    return res.status(400).json({ error: 'Project name missing; ensure projectId is set.' });
  }
  throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/941397c8fc90f89d. Report an issue: GitHub.