{"record":{"id":"bf083c826cd02007","repo":"nexu-io/open-design","slug":"vercel-token-is-required","errorCode":null,"errorMessage":"Vercel token is required.","messagePattern":"Vercel token is required\\.","errorType":"http","errorClass":"DeployError","httpStatus":400,"severity":"error","filePath":"apps/daemon/src/deploy.ts","lineNumber":390,"sourceCode":"      file: safePath,\n      data: projectFile.buffer,\n      contentType: projectFile.mime,\n      sourcePath: safePath,\n    });\n  }\n}\n\nfunction isLinkedFolderProject(metadata: unknown) {\n  return Boolean(\n    metadata\n      && typeof metadata === 'object'\n      && typeof (metadata as { baseDir?: unknown }).baseDir === 'string',\n  );\n}\n\nexport async function deployToVercel({ config, files, projectId }: { config: DeployConfig; files: DeployFile[]; projectId: string }) {\n  if (!config?.token) {\n    throw new DeployError('Vercel token is required.', 400);\n  }\n\n  const createResp = await fetch(`${VERCEL_API}/v13/deployments${vercelTeamQuery(config)}`, {\n    method: 'POST',\n    headers: {\n      Authorization: `Bearer ${config.token}`,\n      'Content-Type': 'application/json',\n    },\n    body: JSON.stringify({\n      name: safeVercelProjectName(`od-${projectId}`),\n      files: files.map((f) => ({\n        file: f.file,\n        data: Buffer.from(f.data).toString('base64'),\n        encoding: 'base64',\n      })),\n      projectSettings: { framework: null },\n    }),\n  });","sourceCodeStart":372,"sourceCodeEnd":408,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/deploy.ts#L372-L408","documentation":"Thrown by deployToVercel in apps/daemon/src/deploy.ts:390 as `DeployError('Vercel token is required.', 400)` when `config?.token` is falsy. The token is the Bearer credential used in the `Authorization` header for every Vercel API call (creating the deployment, polling status). Without it the function cannot make any authenticated request.","triggerScenarios":"Calling `deployToVercel({ config, files, projectId })` where `config.token` is empty/undefined. This means `readVercelConfig()` returned an empty token (vercel.json absent or token field missing) and the user never saved credentials.","commonSituations":"Deploying before completing Vercel setup; vercel.json under OD_USER_STATE_DIR was deleted or corrupted; team migration wiped credentials; the UI allowed clicking Deploy before the token was persisted.","solutions":["Save a Vercel access token first via writeVercelConfig({ token }) (generate one at vercel.com -> Settings -> Tokens).","Confirm vercel.json exists at deployConfigPath(VERCEL_PROVIDER_ID) and contains a non-empty `token` string.","If using a team, also supply teamId/teamSlug so the token resolves to the right scope."],"exampleFix":"// before\nawait deployToVercel({ config: { token: '' }, files, projectId });\n\n// after\nawait writeVercelConfig({ token: process.env.VERCEL_TOKEN });\nconst config = await readVercelConfig();\nawait deployToVercel({ config, files, projectId });","handlingStrategy":"validation","validationCode":"const config = await readVercelConfig();\nif (!config.token) {\n  return res.status(400).json({ error: 'Save a Vercel access token first.' });\n}\nawait deployToVercel({ config, files, projectId });","typeGuard":"function hasVercelToken(config: Partial<DeployConfig>): config is DeployConfig & { token: string } {\n  return typeof config.token === 'string' && config.token.length > 0;\n}","tryCatchPattern":"try {\n  await deployToVercel({ config, files, projectId });\n} catch (err) {\n  if (err instanceof DeployError && err.status === 400 && /Vercel token/i.test(err.message)) {\n    return res.status(400).json({ error: 'Configure Vercel credentials before deploying.' });\n  }\n  throw err;\n}","preventionTips":["Run writeVercelConfig({ token }) during onboarding before exposing the Deploy button.","Disable Deploy until readVercelConfig().token is non-empty.","Store the token in vercel.json (mode 0600) — never hardcode it in source."],"tags":["deploy","vercel","validation","credentials"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}