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

  1. Verify the runtime URL is reachable from the WeCom bridge host and matches where the runtime actually listens
  2. Re-export CODEWHALE_RUNTIME_TOKEN with the current runtime token
  3. Confirm the thread exists via GET /v1/threads/{threadId} with the same auth headers; recreate if pruned
  4. 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

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


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/aea7d17e08a24571. Report an issue: GitHub.