{"record":{"id":"5abb067c81fa5bdc","repo":"redis/node-redis","slug":"http-response-status-text","errorCode":null,"errorMessage":"HTTP ${response.status} - ${text}","messagePattern":"HTTP (.+?) - (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/test-utils/lib/fault-injector/fault-injector-client.ts","lineNumber":224,"sourceCode":"\n    // Add timeout to fetch using AbortController\n    const controller = new AbortController();\n    const timeoutId = globalThis.setTimeout(() => {\n      controller.abort();\n    }, timeoutMs);\n\n    try {\n      const response = await this.#fetch(url, {\n        method,\n        headers,\n        body: payload,\n        signal: controller.signal\n      });\n\n      if (!response.ok) {\n        try {\n          const text = await response.text();\n          throw new Error(`HTTP ${response.status} - ${text}`);\n        } catch {\n          throw new Error(`HTTP ${response.status}`);\n        }\n      }\n\n      try {\n        const result = (await response.json()) as T;\n        return result;\n      } catch {\n        throw new Error(\n          `HTTP ${response.status} - Unable to parse response as JSON`\n        );\n      }\n    } finally {\n      globalThis.clearTimeout(timeoutId);\n    }\n  }\n","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/redis/node-redis/blob/90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58/packages/test-utils/lib/fault-injector/fault-injector-client.ts#L206-L242","documentation":"Intended to be thrown by #request when the fault-injector HTTP response is not ok AND the body text could be read, embedding the body for diagnostics. HOWEVER this throw lives INSIDE the try block whose catch (next line) throws error 113, so the throw here is always caught and error 112 is effectively masked — callers never receive it. The body text is lost. This is a bug: the throw should be moved outside the try.","triggerScenarios":"Any non-ok HTTP response from the fault-injector REST API where response.text() resolves. Due to the catch bug, the caller receives error 113 ('HTTP <status>') without the body instead.","commonSituations":"4xx/5xx from the fault-injector service (bad parameters, not found, server error); the developer sees error 113 and loses the explanatory body text, making diagnosis harder.","solutions":["Patch #request so the throw is outside the try: read text in the try, throw after it","Until patched, reproduce the request manually (curl) to see the body the library discards","Pass a custom fetchImpl to the FaultInjectorClient that logs response bodies for debugging"],"exampleFix":"// before — throw inside try is swallowed by catch (bug)\nif (!response.ok) {\n  try {\n    const text = await response.text();\n    throw new Error(`HTTP ${response.status} - ${text}`);\n  } catch {\n    throw new Error(`HTTP ${response.status}`);\n  }\n}\n\n// after — read in try, throw outside\nif (!response.ok) {\n  let text: string | undefined;\n  try { text = await response.text(); } catch { /* ignore */ }\n  throw new Error(text ? `HTTP ${response.status} - ${text}` : `HTTP ${response.status}`);\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await fi.listActions();\n} catch (e) {\n  if (e instanceof Error && /HTTP \\d{3}/.test(e.message)) {\n  }\n  throw e;\n}","preventionTips":["Patch #request so the body-including throw is not caught by its own catch (move throw outside try)","Until patched, reproduce failing requests with curl to read the hidden body","Inject a logging fetchImpl into FaultInjectorClient to capture response bodies during debugging"],"tags":["fault-injection","http","test-utils","bug","error-handling"],"backgroundTag":null,"analyzedSha":"90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58","analyzedAt":"2026-08-11T15:37:21.243Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}