Hmbown/CodeWhale · error · Error
Runtime API request failed (${status}): ${message}
Error message
Runtime API request failed (${status}): ${message} What it means
The WeCom bridge's event pump fetches `${config.runtimeUrl}/v1/threads/{threadId}/events?since_seq=`; a non-ok response is parsed with readJsonSafe and rethrown via compactRuntimeError as `Runtime API request failed (${status}): ${message}`. Malformed SSE records inside an otherwise-200 stream are only logged and skipped, so this throw strictly means the HTTP request itself failed. runtimeUrl defaults to CODEWHALE_RUNTIME_URL or http://127.0.0.1:7878 (index.mjs:39) and the token is CODEWHALE_RUNTIME_TOKEN (index.mjs:40).
Source
Thrown at integrations/wecom-bridge/src/index.mjs:317
async function streamTurnEvents(chatId, frame, threadId, turnId, sinceSeq) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), config.turnTimeoutMs);
const streamId = generateReqId("stream");
let responseText = "";
let latestSeq = sinceSeq;
try {
const response = await fetch(
`${config.runtimeUrl}/v1/threads/${encodeURIComponent(threadId)}/events?since_seq=${sinceSeq}`,
{
headers: authHeaders(),
signal: controller.signal
}
);
if (!response.ok) {
const body = await readJsonSafe(response);
throw new Error(compactRuntimeError(response.status, body));
}
for await (const event of readSse(response)) {
if (!event.data) continue;
let record;
try {
record = JSON.parse(event.data);
} catch (error) {
console.warn("Skipping malformed runtime SSE event:", publicBridgeError(error));
continue;
}
latestSeq = Math.max(latestSeq, Number(record.seq || 0));
await threadStore.patchChat(chatId, { lastSeq: latestSeq });
if (turnId && record.turn_id && record.turn_id !== turnId) continue;
if (record.event === "item.delta" && record.payload?.kind === "agent_message") {
responseText += record.payload.delta || "";View on GitHub (pinned to 8880682c63)
Solutions
- Verify the runtime URL is reachable from the WeCom bridge host and matches where the runtime actually listens
- Re-export CODEWHALE_RUNTIME_TOKEN with the current runtime token
- Confirm the thread exists via GET /v1/threads/{threadId} with the same auth headers; recreate if pruned
- Read the text after the status — it is the runtime's own error message and pinpoints the cause
Example fix
# before: bridge on default port while runtime listens on 7879 # after export CODEWHALE_RUNTIME_URL=http://127.0.0.1:7879
Defensive patterns
Strategy: retry
Validate before calling
const probe = await fetch(
`${config.runtimeUrl}/v1/threads/${encodeURIComponent(threadId)}`,
{ headers: authHeaders() }
);
if (!probe.ok) {
console.error(`runtime preflight failed: ${probe.status}`);
process.exit(2);
} Try / catch
try {
await streamThreadEvents(threadId, sinceSeq);
} catch (error) {
const status = Number(error.message.match(/Runtime API request failed \((\d+)\)/)?.[1]);
if (status >= 500) { await backoffAndRetry(); return; }
throw error;
} Prevention
- Start the runtime before the WeCom bridge and health-check it in the unit ordering
- Keep bridge and runtime tokens in one shared secret so they rotate together
- Persist lastSeq per chat so stream failures resume instead of replaying
When it happens
Trigger: 401 when CODEWHALE_RUNTIME_TOKEN does not match the runtime; 404 for an unknown or pruned threadId; 5xx when the runtime is failing; CODEWHALE_RUNTIME_URL pointing at a stale port or host.
Common situations: WeCom callback server started before the runtime is up; token drift between the TUI runtime and the bridge deployment; chat-state threadIds the runtime no longer retains after a restart.
Related errors
- Runtime API request failed (${status}): ${message}
- Runtime API request failed (${status}): ${message}
- DeepSeek ${res.status}: ${text}
- Runtime API request failed (${status}): ${message}
- Runtime API request failed (${status}): ${message}
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/aea7d17e08a24571.
Report an issue: GitHub.