{"record":{"id":"86778e07c9a7732a","repo":"Hmbown/CodeWhale","slug":"runtime-api-request-failed-status-message-86778e","errorCode":null,"errorMessage":"Runtime API request failed (${status}): ${message}","messagePattern":"Runtime API request failed \\((.+?)\\): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"integrations/weixin-bridge/src/index.mjs","lineNumber":208,"sourceCode":"  };\n}\n\nasync function readJsonSafe(response) {\n  try {\n    return await response.json();\n  } catch {\n    return null;\n  }\n}\n\nasync function runtimeJson(subPath, { method = \"GET\", body = null, auth = true } = {}) {\n  const url = `${config.runtimeUrl}${subPath}`;\n  const options = { method, headers: auth ? authHeaders() : {} };\n  if (body) options.body = JSON.stringify(body);\n  const response = await fetch(url, options);\n  const result = await readJsonSafe(response);\n  if (!response.ok) {\n    throw new Error(compactRuntimeError(response.status, result));\n  }\n  return result;\n}\n\nasync function* readSse(response) {\n  let buffer = \"\";\n  for await (const chunk of response.body) {\n    buffer += new TextDecoder().decode(chunk, { stream: true });\n    const lines = buffer.split(\"\\n\");\n    buffer = lines.pop() || \"\";\n    for (const line of lines) {\n      const trimmed = line.trim();\n      if (!trimmed) continue;\n      if (trimmed.startsWith(\"data:\")) {\n        yield { data: trimmed.slice(5).trim() };\n      } else if (trimmed.startsWith(\"event:\")) {\n        yield { event: trimmed.slice(6).trim() };\n      } else if (trimmed.startsWith(\"id:\")) {","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/integrations/weixin-bridge/src/index.mjs#L190-L226","documentation":"runtimeJson is the weixin-bridge's shared helper for every runtime call: it builds `${config.runtimeUrl}${subPath}`, optionally JSON-stringifies the body, and throws `Runtime API request failed (${status}): ${compactRuntimeError...}` whenever response.ok is false. Because all runtime GET/POSTs funnel through it, the failing endpoint is identified by the subPath used at the call site.","triggerScenarios":"Any /v1/... request returning non-OK: 401 for a bad runtime token, 404 for unknown thread/turn ids in the subPath, 400 for a malformed request body, 5xx when the runtime itself crashes.","commonSituations":"Weixin bridge configured with a stale runtimeUrl; auth token rejected after rotation; passing ids the runtime pruned (old turns or threads).","solutions":["Reproduce with curl against `${config.runtimeUrl}${subPath}` using the same auth headers to see the raw status and body","Align the runtime URL and token env values with what the runtime currently accepts, then retry","For 400s, log the request body — the runtime's message names the invalid field","For 5xx, inspect runtime logs; the bridge is a thin client and cannot fix server-side failures"],"exampleFix":"# before: 401 from a token issued by an older runtime\nCODEWHALE_RUNTIME_TOKEN=old node src/index.mjs\n# after\nCODEWHALE_RUNTIME_TOKEN=current node src/index.mjs","handlingStrategy":"retry","validationCode":"const probe = await fetch(config.runtimeUrl, { headers: authHeaders() });\nif (!probe.ok && probe.status >= 500) {\n  console.error('runtime unhealthy — delaying bridge work');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await runtimeJson(subPath, { method, body });\n} catch (error) {\n  const status = Number(error.message.match(/Runtime API request failed \\((\\d+)\\)/)?.[1]);\n  if (status >= 500 || status === 429) { await delay(1000); return runtimeJson(subPath, { method, body }); }\n  throw error;\n}","preventionTips":["Centralize runtime calls through runtimeJson so failures carry status context","Smoke-test the runtime URL/token pair at bridge startup"],"tags":["network","api","runtime","weixin-bridge"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}