Hmbown/CodeWhale · error

${compactRuntimeError(response.status, body)}

Error message

${compactRuntimeError(response.status, body)}

What it means

In the WeCom bridge's streamTurnEvents, a non-OK HTTP response from the runtime's SSE endpoint triggers compactRuntimeError(response.status, body), which merges the status code and JSON error details into the thrown message. This converts transport-level failures (auth rejection, bad URL, server errors) into an explicit, diagnosable error before any SSE parsing begins.

Solutions

  1. Decode the status in the message and address it: fix credentials for 401/403, fix runtimeUrl for 404, inspect runtime logs for 5xx.
  2. Confirm the runtime service is up and reachable at the configured URL.
  3. Refresh the token/secret feeding authHeaders().

Example fix

// before
WECOM_BRIDGE_RUNTIME_URL=http://127.0.0.1:9999  # nothing listening / wrong path
// Error: 404 ...

// after
WECOM_BRIDGE_RUNTIME_URL=http://127.0.0.1:8080  # actual runtime address
Defensive patterns

Strategy: try-catch

Validate before calling

const base = process.env.WECOM_BRIDGE_RUNTIME_URL;
const res = await fetch(`${base}/health`);
if (!res.ok) throw new Error(`Runtime unavailable: HTTP ${res.status}`);

Try / catch

try {
  for await (const event of streamTurnEvents(input)) {
    handle(event);
  }
} catch (err) {
  if (/^40[13]/.test(err.message)) {
    await reauthenticate();
  } else if (/^5\d\d/.test(err.message)) {
    scheduleRetry();
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: fetch to the turn-events endpoint resolves with response.ok false — 401/403 for bad auth headers, 404 for a wrong runtime URL/path, or 5xx when the runtime crashes or a proxy fails.

Common situations: WeCom bridge pointed at the wrong runtime port, missing/expired credentials, runtime under load returning 502/503 through a proxy, or version skew between bridge and runtime endpoints.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/44be079bf4bb39fd. Report an issue: GitHub.

Appendix: 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 433685b202)