{"record":{"id":"d5787f6bde955c21","repo":"abhigyanpatwari/GitNexus","slug":"err-terminalmessage","errorCode":null,"errorMessage":"${err.terminalMessage}","messagePattern":"\\$\\{err\\.terminalMessage\\}","errorType":"exception","errorClass":"HttpEmbeddingError","httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/embeddings/http-client.ts","lineNumber":504,"sourceCode":"          sleep: (ms) => abortableSleep(ms, requestOptions.signal),\n        },\n      },\n    );\n  } catch (err) {\n    if (\n      requestOptions.signal?.aborted ||\n      (err instanceof DOMException && err.name === 'AbortError')\n    ) {\n      throw new HttpEmbeddingError(\n        `Embedding request cancelled (${safeUrl(url)}, batch ${batchIndex})`,\n        { cause: err },\n      );\n    }\n    // Retries are exhausted on a bad 2xx body. Surface the message the sentinel\n    // carried, keeping the underlying parse error in `cause` only — the body\n    // text must never reach the `sanitizeReason` fallback and leak to stderr.\n    if (err instanceof RetryableEmbeddingBodyError) {\n      throw new HttpEmbeddingError(err.terminalMessage, { cause: err.cause });\n    }\n    if (err instanceof CircuitOpenError) {\n      throw new HttpEmbeddingError(\n        `Embedding endpoint circuit open (${safeUrl(url)}, batch ${batchIndex}): retry in ${Math.ceil(err.retryAfterMs / 1000)}s`,\n        { cause: err },\n      );\n    }\n    if (err instanceof DOMException && err.name === 'TimeoutError') {\n      throw new HttpEmbeddingError(\n        `Embedding request timed out after ${timeoutMs}ms (${safeUrl(url)}, batch ${batchIndex})`,\n        { cause: err },\n      );\n    }\n    if (err instanceof ResilientFetchExhaustedError) {\n      throw new HttpEmbeddingError(\n        `Embedding endpoint returned ${err.response.status} (${safeUrl(url)}, batch ${batchIndex})`,\n        { cause: err },\n      );","sourceCodeStart":486,"sourceCodeEnd":522,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/gitnexus/src/core/embeddings/http-client.ts#L486-L522","documentation":"An HttpEmbeddingError thrown from httpEmbedBatch's catch block when a RetryableEmbeddingBodyError (errors 123/124/125) has exhausted all retries inside resilientFetch. It surfaces the sentinel's terminalMessage verbatim (so the operator sees \"unparseable response\", \"unexpected response shape\", or the count-mismatch wording) and keeps the underlying parse error only in `cause`, ensuring the raw body text never reaches the sanitizeReason fallback or stderr. This is the terminal, user-visible form of a persistently bad 2xx body.","triggerScenarios":"httpEmbedBatch after resilientFetch gives up: the fetchImpl callback threw RetryableEmbeddingBodyError on every attempt (maxAttempts, default HTTP_MAX_RETRIES+1 = 3). Whichever body fault (unparseable / wrong shape / count mismatch) recurred on the final attempt determines the message text carried in err.terminalMessage.","commonSituations":"Persistent wrong-endpoint configuration (always returns HTML). Provider schema mismatch that never resolves on retry. Provider input-count cap always truncating. Any of errors 123/124/125 that is deterministic rather than transient.","solutions":["Read the surfaced terminalMessage: if it says \"unparseable\", follow error 123's fixes; \"unexpected response shape\" → error 124; \"N vectors for M texts\" → error 125.","Inspect err.cause for the raw parse error if you need the underlying detail (it is intentionally kept out of the user-facing message).","Because retries are exhausted, the fault is deterministic — fix the endpoint configuration/schema rather than expecting another retry to help.","Run the curl probe from error 123 against the configured URL+model to reproduce the bad body in isolation."],"exampleFix":"// before: terminalMessage says \"unparseable response\"\n// (endpoint returns HTML)\nexport GITNEXUS_EMBEDDING_URL=https://provider.example.com\n\n// after\nexport GITNEXUS_EMBEDDING_URL=https://provider.example.com/v1","handlingStrategy":"try-catch","validationCode":"// No pre-call validation prevents a deterministic body fault; instead, probe once:\nconst r = await fetch(`${URL}/embeddings`, { /* ... */ });\ntry {\n  const j = await r.json();\n  if (!Array.isArray(j?.data)) throw new Error('bad shape');\n} catch {\n  throw new Error('Endpoint body is not usable; see errors 123/124/125');\n}","typeGuard":"import { isHttpEmbeddingError } from 'gitnexus';\nconst isTerminalBodyError = (e: unknown): boolean =>\n  isHttpEmbeddingError(e) &&\n  e instanceof Error &&\n  (e.message.includes('unparseable response') ||\n   e.message.includes('unexpected response shape') ||\n   /vectors for \\d+ texts/.test(e.message));","tryCatchPattern":"try {\n  await httpEmbed(texts);\n} catch (e) {\n  if (isTerminalBodyError(e)) {\n    // retries exhausted on a bad body: this is deterministic, do not retry blindly;\n    // inspect e.cause for the raw parse error, then fix the endpoint config.\n  }\n  throw e;\n}","preventionTips":["Probe the endpoint with curl at deploy time so deterministic body faults surface before a long run.","Keep endpoint config (URL, model) in version-controlled env so a regression is visible in diff.","Do not blindly retry a terminal body error — it indicates a config/schema problem, not a transient blip."],"tags":["endpoint","response-body","retry-exhausted","embeddings"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}