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
- Decode the status in the message and address it: fix credentials for 401/403, fix runtimeUrl for 404, inspect runtime logs for 5xx.
- Confirm the runtime service is up and reachable at the configured URL.
- 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
- Verify runtimeUrl/host/port against the runtime's actual listen address before deploying.
- Refresh credentials proactively; treat 401 as a signal to rotate tokens.
- Add proxy/load-balancer health checks so 502/503 is caught upstream of the bridge.
- Keep bridge and runtime endpoint versions aligned.
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
- ${compactRuntimeError(response.status, body)}
- ${compactRuntimeError(response.status, body)}
- ${compactRuntimeError(response.status, body)}
- ${compactRuntimeError(response.status, result)}
- Stream read error
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)