nexu-io/open-design · error · Error
no Volcengine Ark API key — configure it in Settings or set
Error message
no Volcengine Ark API key — configure it in Settings or set ARK_API_KEY
What it means
Thrown at the top of `renderVolcengineVideo` (Doubao Seedance) when no Volcengine Ark API key is available. The renderer cannot authenticate the `POST /api/v3/contents/generations/tasks` call, so it fails fast with an actionable message naming the `ARK_API_KEY` env var and the Settings UI.
Source
Thrown at apps/daemon/src/media/index.ts:1400
suggestedExt: format === 'opus' ? '.ogg' : `.${format}`,
};
}
// ---------------------------------------------------------------------------
// Provider: Volcengine Ark — Doubao Seedance 2.0 video.
//
// Docs:
// POST /api/v3/contents/generations/tasks → { id }
// GET /api/v3/contents/generations/tasks/{id} → { status, content: { video_url } }
// We submit, poll until succeeded/failed, then fetch the produced
// video_url and return the raw bytes. The temporary URL Volcengine
// returns is only valid for ~24h, so streaming the bytes into the
// project folder is required to keep them addressable.
// ---------------------------------------------------------------------------
async function renderVolcengineVideo(ctx: MediaContext, credentials: ProviderConfig, onProgress?: ProgressFn): Promise<RenderResult> {
if (!credentials.apiKey) {
throw new Error(
'no Volcengine Ark API key — configure it in Settings or set ARK_API_KEY',
);
}
const baseUrl = (credentials.baseUrl || 'https://ark.cn-beijing.volces.com/api/v3').replace(/\/$/, '');
// Seedance accepts inline `--resolution`, `--duration`, `--ratio` and
// `--camerafixed` flags inside the prompt text. We append a flags
// suffix so user prompts that already contain them still win.
const ratio = volcengineRatioFor(ctx.aspect);
const durationSec = ctx.length || 5;
const resolution = '720p';
const promptText = (ctx.prompt && ctx.prompt.trim()) || 'A short cinematic clip.';
const suffixFlags: string[] = [];
if (!/--resolution\b/.test(promptText)) suffixFlags.push(`--resolution ${resolution}`);
if (!/--duration\b/.test(promptText)) suffixFlags.push(`--duration ${durationSec}`);
if (!/--ratio\b/.test(promptText)) suffixFlags.push(`--ratio ${ratio}`);
const fullText = suffixFlags.length
? `${promptText} ${suffixFlags.join(' ')}`View on GitHub (pinned to 5be4028344)
Solutions
- Set `ARK_API_KEY` in the daemon's environment (or export it in the shell that launches `tools-dev`), or enter the key under Settings → Providers → Volcengine.
- Restart the daemon after adding the key so `resolveProviderConfig` re-reads it.
- Confirm the selected model is actually a Volcengine model and not an aliased one routed elsewhere.
Example fix
// before // (no key configured, Seedance model selected) od media generate --surface video --model doubao-seedance-1-0-t2v --prompt '...' // after export ARK_API_KEY=sk-xxxx # in the shell that runs tools-dev od media generate --surface video --model doubao-seedance-1-0-t2v --prompt '...'
Defensive patterns
Strategy: validation
Validate before calling
function ensureVolcengineCreds(credentials: ProviderConfig): void {
if (!credentials.apiKey) {
throw new Error('no Volcengine Ark API key — configure it in Settings or set ARK_API_KEY');
}
}
// call before renderVolcengineVideo(ctx, credentials, onProgress)
ensureVolcengineCreds(credentials); Type guard
function hasVolcengineCreds(c: ProviderConfig): c is ProviderConfig & { apiKey: string } {
return typeof c.apiKey === 'string' && c.apiKey.length > 0;
} Prevention
- Set `ARK_API_KEY` in the shell that launches the daemon, not just your editor.
- Restart the daemon after adding a key so `resolveProviderConfig` re-reads it.
- Gate model selection on whether a Volcengine credential is configured.
When it happens
Trigger: `credentials.apiKey` is falsy after `resolveProviderConfig('volcengine')` resolves the key from Settings, `ARK_API_KEY`, or media-config, while the selected model is a `provider: 'volcengine'` video model (e.g. `doubao-seedance-*`).
Common situations: (1) Fresh install where the user picked a Seedance model before adding a key; (2) `ARK_API_KEY` set in a different shell than the one running the daemon; (3) key cleared from Settings but model selection persisted.
Related errors
- volcengine task create ${taskResp.status}: ${truncate(taskTe
- volcengine non-JSON: ${truncate(taskText, 200)}
- volcengine task response missing id
- volcengine poll ${pollResp.status}: ${truncate(pollText, 240
- volcengine poll non-JSON: ${truncate(pollText, 200)}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/4321ccb66d1fcdaf.
Report an issue: GitHub.