nexu-io/open-design · error · DeployError
Vercel token is required.
Error message
Vercel token is required.
What it means
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.
Source
Thrown at apps/daemon/src/deploy.ts:390
file: safePath,
data: projectFile.buffer,
contentType: projectFile.mime,
sourcePath: safePath,
});
}
}
function isLinkedFolderProject(metadata: unknown) {
return Boolean(
metadata
&& typeof metadata === 'object'
&& typeof (metadata as { baseDir?: unknown }).baseDir === 'string',
);
}
export async function deployToVercel({ config, files, projectId }: { config: DeployConfig; files: DeployFile[]; projectId: string }) {
if (!config?.token) {
throw new DeployError('Vercel token is required.', 400);
}
const createResp = await fetch(`${VERCEL_API}/v13/deployments${vercelTeamQuery(config)}`, {
method: 'POST',
headers: {
Authorization: `Bearer ${config.token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: safeVercelProjectName(`od-${projectId}`),
files: files.map((f) => ({
file: f.file,
data: Buffer.from(f.data).toString('base64'),
encoding: 'base64',
})),
projectSettings: { framework: null },
}),
});View on GitHub (pinned to 5be4028344)
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.
Example fix
// before
await deployToVercel({ config: { token: '' }, files, projectId });
// after
await writeVercelConfig({ token: process.env.VERCEL_TOKEN });
const config = await readVercelConfig();
await deployToVercel({ config, files, projectId }); Defensive patterns
Strategy: validation
Validate before calling
const config = await readVercelConfig();
if (!config.token) {
return res.status(400).json({ error: 'Save a Vercel access token first.' });
}
await deployToVercel({ config, files, projectId }); Type guard
function hasVercelToken(config: Partial<DeployConfig>): config is DeployConfig & { token: string } {
return typeof config.token === 'string' && config.token.length > 0;
} Try / catch
try {
await deployToVercel({ config, files, projectId });
} catch (err) {
if (err instanceof DeployError && err.status === 400 && /Vercel token/i.test(err.message)) {
return res.status(400).json({ error: 'Configure Vercel credentials before deploying.' });
}
throw err;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Cloudflare API token is required.
- Only HTML files can be deployed.
- Could not deploy referenced files (${parts.join('; ')}).
- Cloudflare account ID is required.
- Cloudflare zone is required for a custom domain.
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/bf083c826cd02007.
Report an issue: GitHub.