{"record":{"id":"da52b4660c90c90f","repo":"TencentCloud/TencentDB-Agent-Memory","slug":"no-upstream-response-available-da52b4","errorCode":null,"errorMessage":"No upstream response available","messagePattern":"No upstream response available","errorType":"http","errorClass":null,"httpStatus":502,"severity":"error","filePath":"MemoryProxy/src/handler.ts","lineNumber":435,"sourceCode":"      }\n      return { resp: upstreamResp, retried: true };\n    } catch (retryErr: unknown) {\n      if (isRateLimitExceededError(retryErr)) throw retryErr;\n      if (retryErr instanceof DOMException && retryErr.name === \"TimeoutError\") {\n        pipe.error(\"RETRY_FORWARD\", `Timeout after ${forwardTimeoutMs / 1000}s`);\n      } else {\n        pipe.error(\"RETRY_FORWARD\", retryErr);\n      }\n      throw new Error(\"Upstream request failed\");\n    }\n  }\n\n  if (forwardFailed && !shouldRetry) {\n    throw new Error(\"Upstream request failed\");\n  }\n\n  if (!upstreamResp) {\n    throw new Error(\"No upstream response available\");\n  }\n\n  return { resp: upstreamResp, retried: false };\n}\n\n/** Main handler for POST /v1/chat/completions (OpenAI compat). */\nexport async function handleChatCompletions(\n  c: Context,\n  config: ProxyConfig,\n): Promise<Response> {\n  const startTime = new Date().toISOString();\n  const traceId = uuidv7();\n\n  // ── Early auth ──────────────────────────────────────────────────────────\n  // Verify BEFORE parsing the body so a rejected caller never triggers body\n  // parsing or the alias-gate. `earlyVerify.userId` is reused later for\n  // both the systemUser short-circuit and the normal pipeline.\n  const earlyAuthHeader = c.req.header(\"authorization\") ?? c.req.header(\"Authorization\") ?? \"\";","sourceCodeStart":417,"sourceCodeEnd":453,"githubUrl":"https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/3efcd317b84146d6a08518ac0f7ee7c8a8d200ec/MemoryProxy/src/handler.ts#L417-L453","documentation":"forwardWithRetry in the MemoryProxy handler throws this when all forward attempts ended without producing an upstream HTTP response object. It signals the proxy could not obtain any response from the upstream LLM API to return to the caller, distinct from an explicit upstream failure. It is the terminal fallback after the retry loop exhausts candidates.","triggerScenarios":"All upstream attempts failed without throwing a retryable 'Upstream request failed' path (forwardFailed false or shouldRetry true) yet upstreamResp remained undefined — e.g. every candidate upstream returned a null/undefined response object, or the forward loop completed with no attempts made because no upstream candidates were configured.","commonSituations":"Proxy config with an empty or misconfigured upstream list; upstream client returning undefined on swallowed errors; load-balancer candidate arrays filtered to zero entries after health checks.","solutions":["Verify the proxy config defines at least one reachable upstream endpoint/api-key pair","Inspect the forward loop logging to see why each attempt yielded no response object (timeouts, aborted requests)","Ensure the upstream client throws instead of returning undefined on failure so the retry path classifies errors","Add a health check / fallback upstream so at least one candidate is always available"],"exampleFix":"// before\nconst resp = await tryForward(url); // returns undefined on error\nif (!upstreamResp) throw new Error(\"No upstream response available\");\n// after\nconst resp = await tryForward(url); // throws on error\nif (!upstreamResp) throw new UpstreamUnavailableError(\"No upstream response after retries\", attempts);","handlingStrategy":"try-catch","validationCode":"// before calling\nif (!config.upstreams || config.upstreams.length === 0) {\n  throw new Error(\"proxy misconfigured: no upstream candidates configured\");\n}","typeGuard":"function hasUpstreamResp(r: unknown): r is Response {\n  return r instanceof Response;\n}","tryCatchPattern":"try {\n  const { resp } = await forwardWithRetry(...);\n} catch (e) {\n  if (e.message === \"No upstream response available\") {\n    return new Response(JSON.stringify({ error: \"upstream_unavailable\" }), { status: 502 });\n  }\n  throw e;\n}","preventionTips":["Always configure at least one healthy upstream candidate","Log each forward attempt's outcome to diagnose silent null responses","Make upstream clients throw instead of returning undefined","Add a 502 mapping in the route handler for this error"],"tags":["proxy","upstream","retry","configuration"],"backgroundTag":"no-upstream-response","analyzedSha":"3efcd317b84146d6a08518ac0f7ee7c8a8d200ec","analyzedAt":"2026-09-01T05:44:22.276Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}