{"record":{"id":"d13d84905f006a4d","repo":"TencentCloud/TencentDB-Agent-Memory","slug":"no-upstream-response-available","errorCode":null,"errorMessage":"No upstream response available","messagePattern":"No upstream response available","errorType":"http","errorClass":null,"httpStatus":502,"severity":"error","filePath":"MemoryProxy/src/anthropicHandler.ts","lineNumber":518,"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/messages (Anthropic Messages API). */\nexport async function handleAnthropicMessages(\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 earlyApiKey = extractApiKey(c);","sourceCodeStart":500,"sourceCodeEnd":536,"githubUrl":"https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/3efcd317b84146d6a08518ac0f7ee7c8a8d200ec/MemoryProxy/src/anthropicHandler.ts#L500-L536","documentation":"End-state guard in forwardWithRetry: forwarding never produced an upstreamResp, and the earlier forwardFailed/shouldRetry conditions did not throw (i.e. failure bookkeeping and retry bookkeeping disagree). The function cannot return a response, so it throws 'No upstream response available'. This usually signals a logic gap where attempts failed without setting forwardFailed, or retries were scheduled but none produced a response.","triggerScenarios":"All forward attempts completed without success yet neither forwardFailed nor the retry path triggered a throw — e.g. attempt bookkeeping not updated on some failure path, shouldRetry true but no attempt was actually re-executed, or an empty attempts list.","commonSituations":"Rare: retry loop refactor leaving upstreamResp unset; non-ok responses treated as retryable without recording failure; streaming responses aborted before assignment.","solutions":["Log upstreamResp/attempt state at each loop iteration to find the path that exits without a response","Ensure every failed attempt sets forwardFailed (or throws) before the loop can exit","Make this error carry the attempt count and last status for debuggability","Add an invariant test: forwardWithRetry always returns a response or throws one of the two defined errors"],"exampleFix":"// before\nif (!upstreamResp) throw new Error(\"No upstream response available\");\n// after\nif (!upstreamResp) throw new Error(`No upstream response available after ${attemptCount} attempts (last=${lastStatus ?? 'none'})`);","handlingStrategy":"try-catch","validationCode":"// no meaningful pre-call validation; it is an internal invariant\nif (typeof forwardWithRetry !== 'function') throw new Error('handler not initialized');","typeGuard":"function isNoUpstreamResponse(e: unknown): boolean {\n  return e instanceof Error && e.message === 'No upstream response available';\n}","tryCatchPattern":"try {\n  return await forwardWithRetry(req, pipe);\n} catch (e) {\n  if (isNoUpstreamResponse(e)) {\n    // logic/invariant gap, not transient: log full context and fail fast\n    pipe.error('NO_UPSTREAM_RESPONSE', e);\n    return jsonError(502, 'proxy produced no upstream response');\n  }\n  throw e;\n}","preventionTips":["Add an invariant test: every forwardWithRetry path returns a response or a defined error","Ensure every failed attempt records forwardFailed before loop exit","Log attempt count and last status at this guard for debuggability","Review retry-loop refactors for paths that skip upstreamResp assignment"],"tags":["proxy","invariant","upstream","logic"],"backgroundTag":"upstream-request-failed","analyzedSha":"3efcd317b84146d6a08518ac0f7ee7c8a8d200ec","analyzedAt":"2026-09-01T05:44:22.276Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}