abhigyanpatwari/GitNexus · error · HttpEmbeddingError

err.terminalMessage (terminal 2xx body error)

Error message

err.terminalMessage (terminal 2xx body error)

What it means

httpEmbedBatch retries requests whose 2xx body cannot be parsed/validated (RetryableEmbeddingBodyError). When retries are exhausted, it throws HttpEmbeddingError whose message is err.terminalMessage — a sanitized sentinel message — with the underlying parse error preserved only in cause. This deliberately keeps raw body text out of the top-level message so it cannot leak to stderr via sanitizeReason fallbacks.

Solutions

  1. Inspect err.cause — it holds the real parse error showing what the body actually looked like structurally.
  2. Verify the endpoint URL actually serves the embedding API and not a proxy/login page (curl the URL).
  3. Check the embedding server version matches the client's expected response schema; upgrade or reconfigure.
  4. Confirm the server is healthy; a 200-with-HTML usually means a gateway misroute.

Example fix

// before: URL points at a gateway root
const url = 'https://gw.internal/';
// after: full embedding API path
const url = 'https://gw.internal/embeddings/v1/embed';
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the endpoint returns JSON embedding responses before batch use
const probe = await fetch(url, { method: 'POST', headers });
const ct = probe.headers.get('content-type') ?? '';
if (!ct.includes('application/json')) throw new Error(`EMBED_URL returns ${ct}; expected JSON`);

Try / catch

try {
  vectors = await httpEmbedBatch(items, opts);
} catch (e) {
  if (e instanceof HttpEmbeddingError && e.cause) {
    console.error('Embedding body parse failed; underlying:', e.cause); // body shape info in cause
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling the HTTP embedding client against an endpoint that returns HTTP 200 with a body that is not the expected embedding JSON (HTML error page, proxy interstitial, wrong schema) on every attempt until maxAttempts is reached.

Common situations: Reverse proxy or API gateway returning an HTML login/error page with status 200; embedding server version returning a different response schema; misconfigured EMBED_URL pointing at a non-embedding service.

Understand the failure class

Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@ac9a4e9abd (2026-09-15). Data as JSON: /api/errors/87885add4659669d. Report an issue: GitHub.

Appendix: source

Thrown at gitnexus/src/core/embeddings/http-client.ts:553

          sleep: (ms) => abortableSleep(ms, requestOptions.signal),
        },
      },
    );
  } catch (err) {
    if (
      requestOptions.signal?.aborted ||
      (err instanceof DOMException && err.name === 'AbortError')
    ) {
      throw new HttpEmbeddingError(
        `Embedding request cancelled (${safeUrl(url)}, batch ${batchIndex})`,
        { cause: err },
      );
    }
    // Retries are exhausted on a bad 2xx body. Surface the message the sentinel
    // carried, keeping the underlying parse error in `cause` only — the body
    // text must never reach the `sanitizeReason` fallback and leak to stderr.
    if (err instanceof RetryableEmbeddingBodyError) {
      throw new HttpEmbeddingError(err.terminalMessage, { cause: err.cause });
    }
    if (err instanceof RetryableEmbeddingTimeoutError) {
      throw new HttpEmbeddingError(
        `${err.message} after ${maxAttempts} attempt(s) (${safeUrl(url)}, batch ${batchIndex})`,
        { cause: err.cause },
      );
    }
    if (err instanceof CircuitOpenError) {
      throw new HttpEmbeddingError(
        `Embedding endpoint circuit open (${safeUrl(url)}, batch ${batchIndex}): retry in ${Math.ceil(err.retryAfterMs / 1000)}s`,
        { cause: err },
      );
    }
    if (err instanceof DOMException && err.name === 'TimeoutError') {
      throw new HttpEmbeddingError(
        `Embedding request timed out after ${timeoutMs}ms (${safeUrl(url)}, batch ${batchIndex})`,
        { cause: err },
      );

View on GitHub (pinned to ac9a4e9abd)