nexu-io/open-design · error · Error
volcengine non-JSON: ${truncate(taskText, 200)}
Error message
volcengine non-JSON: ${truncate(taskText, 200)} What it means
Thrown when `JSON.parse(taskText)` throws on the task-creation response. Volcengine (or an intermediary) returned a 2xx body that isn't JSON — typically an HTML error/gateway page — so the dispatcher surfaces up to 200 chars for diagnosis instead of an opaque parse error.
Source
Thrown at apps/daemon/src/media/index.ts:1455
};
const taskResp = await fetch(`${baseUrl}/contents/generations/tasks`, withMediaRequestInit(ctx, {
method: 'POST',
headers: {
'authorization': `Bearer ${credentials.apiKey}`,
'content-type': 'application/json',
},
body: JSON.stringify(taskBody),
}));
const taskText = await taskResp.text();
if (!taskResp.ok) {
throw new Error(`volcengine task create ${taskResp.status}: ${truncate(taskText, 240)}`);
}
let taskData: any;
try {
taskData = JSON.parse(taskText);
} catch {
throw new Error(`volcengine non-JSON: ${truncate(taskText, 200)}`);
}
const taskId = taskData && taskData.id;
if (!taskId) throw new Error('volcengine task response missing id');
// Poll until succeeded/failed. Keep a hard cap, but make it long
// enough for real Seedance queues: fast t2v often returns in 30-120s,
// while i2v and busy-region t2v can exceed the old 6-minute ceiling.
const startedAt = Date.now();
const configuredMaxMs = Number(process.env.OD_VOLCENGINE_VIDEO_MAX_POLL_MS);
const maxMs =
Number.isFinite(configuredMaxMs) && configuredMaxMs >= 60_000
? configuredMaxMs
: 12 * 60 * 1000;
let videoUrl: string | null = null;
let lastStatus = '';
// Emit a "task accepted" line right away so the agent's chat shows
// something within the first second instead of going silent for the
// full poll loop. cc's Bash tool considers a long-quiet pipe stuckView on GitHub (pinned to 5be4028344)
Solutions
- Inspect the truncated body — HTML (`<html`/`<title>`) points to a gateway/proxy; fix routing or wait out the outage.
- Verify `credentials.baseUrl` (or unset it to use the default `ark.cn-beijing.volces.com`).
- If on a restricted network, ensure the Ark host is reachable and not redirected.
Defensive patterns
Strategy: try-catch
Validate before calling
// Reject HTML/gateway bodies before JSON.parse ever runs.
function looksLikeArkJson(text: string): boolean {
const head = text.slice(0, 100).trim();
return head.startsWith('{') || head.startsWith('[');
}
if (!looksLikeArkJson(taskText)) {
throw new Error(`volcengine non-JSON (not an Ark body): ${truncate(taskText, 200)}`);
} Try / catch
try { taskData = JSON.parse(taskText); }
catch { throw new Error(`volcengine non-JSON: ${truncate(taskText, 200)}`); } Prevention
- Confirm the daemon host can reach `ark.cn-beijing.volces.com` without an HTML redirect.
- Avoid overriding `baseUrl` unless you control the target.
- Log the response `Content-Type` header to catch gateway HTML early.
When it happens
Trigger: 2xx task-creation response that fails `JSON.parse`. Causes: a captive-portal/HTML auth wall, a Volcengine gateway returning an HTML 502/504 maintenance page with a 2xx status, or a `baseUrl` override pointing at a non-Ark host that serves HTML.
Common situations: (1) Behind a captive portal or corporate proxy injecting an HTML interstitial; (2) Volcengine regional outage surfacing an HTML status page with a 2xx status; (3) `baseUrl` mistyped to a path that serves HTML.
Related errors
- volcengine poll non-JSON: ${truncate(pollText, 200)}
- volcengine image non-JSON: ${truncate(text, 200)}
- no Volcengine Ark API key — configure it in Settings or set
- volcengine task create ${taskResp.status}: ${truncate(taskTe
- volcengine task response missing id
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/0ff8d6386362e97a.
Report an issue: GitHub.