{"record":{"id":"37cbe36cc1644b7c","repo":"TencentCloud/TencentDB-Agent-Memory","slug":"backend-api-error-res-statuscode-data","errorCode":null,"errorMessage":"Backend API error ${res.statusCode}: ${data}","messagePattern":"Backend API error (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"MemoryCore/src/offload/backend-client.ts","lineNumber":328,"sourceCode":"          method: \"POST\",\n          headers: reqHeaders,\n          ...(isHttps ? { rejectUnauthorized: false } : {}),\n        },\n        (res) => {\n          let data = \"\";\n          res.on(\"data\", (chunk: Buffer) => {\n            data += chunk.toString();\n          });\n          res.on(\"end\", () => {\n            clearTimeout(timer);\n            const durationMs = Date.now() - startMs;\n\n            if (!res.statusCode || res.statusCode < 200 || res.statusCode >= 300) {\n              this.logger.warn(\n                `[context-offload] HTTP <<< ${path}: ${res.statusCode} ${res.statusMessage} (${durationMs}ms) body=${data.slice(0, 500)}`,\n              );\n              reject(new Error(`Backend API error ${res.statusCode}: ${data}`));\n              return;\n            }\n\n            try {\n              const parsed = JSON.parse(data) as T;\n              this.logger.debug?.(\n                `[context-offload] HTTP <<< ${path}: ${res.statusCode} (${durationMs}ms, ${data.length} bytes)`,\n              );\n              resolve(parsed);\n            } catch {\n              reject(new Error(`Backend response JSON parse error: ${data.slice(0, 500)}`));\n            }\n          });\n        },\n      );\n\n      req.on(\"error\", (err: Error) => {\n        clearTimeout(timer);\n        const durationMs = Date.now() - startMs;","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/3efcd317b84146d6a08518ac0f7ee7c8a8d200ec/MemoryCore/src/offload/backend-client.ts#L310-L346","documentation":"BackendClient.post performs a raw Node http/https POST to the context-offload backend and rejects the returned Promise with `Backend API error <statusCode>: <body>` whenever the response status is missing or outside 200-299. Unlike the offload-client warnings, this is a real rejection: callers awaiting post() will see a thrown Error containing the status code and up to the full response body for diagnostics.","triggerScenarios":"Any BackendClient.post() call whose HTTP response is non-2xx: 401 when Authorization Bearer apiKey is absent/wrong, 404 when the backend base URL or path is wrong, 400 on malformed payload to /store or report endpoints, 429 rate limiting, or 5xx backend errors. Also fires if statusCode is undefined (malformed response).","commonSituations":"Backend service not deployed at the configured URL (ECONNREFUSED is separate, but 404 indicates wrong path); missing BACKEND_API_KEY so Authorization header is skipped and server returns 401; backend rejecting large /store payloads; corporate proxy returning 403/502; userIdFn/taskIdFn producing headers the backend refuses.","solutions":["Inspect the status code and body embedded in the error message — the body usually contains the backend's own error explanation.","401/403 → set/rotate the apiKey passed to BackendClient so the Authorization header is sent.","404 → verify the backend base URL and endpoint path in the client configuration.","5xx/429 → check backend service health/logs and add retry with backoff around post() calls.","Ensure callers of post() wrap awaits in try/catch, since this rejection propagates (unlike the fire-and-forget offload-client paths)."],"exampleFix":"// before: unhandled rejection on non-2xx\nawait backendClient.post(\"/store\", payload);\n// after: catch and degrade gracefully\ntry {\n  await backendClient.post(\"/store\", payload);\n} catch (err) {\n  logger.warn(`context-offload store skipped: ${err instanceof Error ? err.message : err}`);\n}","handlingStrategy":"try-catch","validationCode":"if (!backendBaseUrl) throw new Error(\"backend base URL not configured\");\nif (!apiKey) logger.warn(\"no API key set — backend will likely return 401\");\ntry { new URL(`${backendBaseUrl}/store`); } catch { throw new Error(\"invalid backend URL\"); }","typeGuard":null,"tryCatchPattern":"try {\n  const res = await backendClient.post<T>(path, payload);\n  // use res\n} catch (err) {\n  const msg = err instanceof Error ? err.message : String(err);\n  const status = /Backend API error (\\d+)/.exec(msg)?.[1];\n  if (status === \"401\" || status === \"403\") {\n    logger.error(`backend auth failed (${status}) — check API key`);\n  } else {\n    logger.warn(`backend post failed, continuing without offload: ${msg}`);\n  }\n}","preventionTips":["Always await post() inside try/catch — it rejects on any non-2xx status.","Configure the apiKey before constructing BackendClient so Authorization is always sent.","Parse the status code out of the error message to branch on 401 vs 429 vs 5xx.","Add retry-with-backoff only for transient statuses (429, 5xx); fail fast on 4xx.","Validate the backend URL with new URL() at startup to catch path typos early."],"tags":["http","backend","rejected-promise","api"],"backgroundTag":"http-non-2xx-response","analyzedSha":"3efcd317b84146d6a08518ac0f7ee7c8a8d200ec","analyzedAt":"2026-09-01T05:44:22.276Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}