abhigyanpatwari/GitNexus · error · RetryableEmbeddingBodyError
Embedding endpoint returned ${received} vectors for ${expect
Error message
Embedding endpoint returned ${received} vectors for ${expected} texts (${safeEndpoint}, batch ${batchIndex}) What it means
A module-private RetryableEmbeddingBodyError thrown inside the retried fetch callback when the body is well-shaped (`data` is an array of embedding items) but its cardinality does not match the request — `payload.data.length !== batch.length`. This catches a 200 carrying `{"data": []}` (vacuously passing the every(isEmbeddingItem) check) or a half-truncated vector list. It is retried and counted against the circuit breaker (#2790), then surfaced terminally as HttpEmbeddingError (127). The message names both counts: e.g. "0 vectors for 64 texts".
Source
Thrown at gitnexus/src/core/embeddings/http-client.ts:473
// `retryable-network` (retried, then `breaker.recordFailure()`): the
// same timeout would take 3 attempts instead of 1, count toward the
// process-global `embeddings-http` breaker, and reach the operator as
// "unparseable response" so they never reach for the timeout knob.
if (isTerminalNetworkError(err)) throw err;
throw new RetryableEmbeddingBodyError(unparseableMessage(), { cause: err });
}
if (!Array.isArray(payload?.data) || !payload.data.every(isEmbeddingItem)) {
throw new RetryableEmbeddingBodyError(unexpectedShapeMessage());
}
// Cardinality belongs *inside* the retry loop. `every(isEmbeddingItem)`
// is vacuously true for `[]` and true for any array shorter than the
// request, so a 200 carrying `{"data": []}` — or half the vectors —
// used to be classified `success`, call `breaker.recordSuccess()`
// (erasing the outage signal), and only then fail terminally after a
// single attempt. A short body is a truncated body: same backoff, same
// breaker accounting as any other endpoint fault (#2790).
if (payload.data.length !== batch.length) {
throw new RetryableEmbeddingBodyError(
countMismatchMessage(payload.data.length, batch.length, safeUrl(url), batchIndex),
);
}
parsed = payload.data;
return attemptResp;
},
breakerKey: HTTP_BREAKER_KEY,
retry: {
maxAttempts,
baseDelayMs: HTTP_RETRY_BACKOFF_MS,
capDelayMs: retryCapMs,
retryAfterCapMs: retryCapMs,
sleep: (ms) => abortableSleep(ms, requestOptions.signal),
},
},
);
} catch (err) {
if (View on GitHub (pinned to d540b00184)
Solutions
- Reduce the effective batch size by embedding smaller text lists in your own driver, or check the provider's per-request input limit and request a raise.
- Inspect a raw multi-input response with curl to see whether the provider is truncating or filtering inputs.
- Pre-truncate over-long input texts to the model's token limit so the provider does not drop them.
- If intermittent (truncation under load), the retry loop should recover it; persistent short bodies indicate a provider cap or filter to fix upstream.
Example fix
// before: provider caps inputs at 32, GitNexus sends 64 // (no direct env; the mismatch is reported per batch) // after: there is no public batch-size env, so front the endpoint // with a proxy that splits requests, or open a request for a // configurable HTTP_BATCH_SIZE override upstream.
Defensive patterns
Strategy: validation
Validate before calling
// Confirm the provider returns one vector per input at your batch size:
const r = await fetch(`${URL}/embeddings`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${KEY}` },
body: JSON.stringify({ model: MODEL, input: ['a', 'b', 'c', 'd'] }),
});
const body = await r.json();
if (!Array.isArray(body?.data) || body.data.length !== 4) {
throw new Error(`Provider returned ${body?.data?.length ?? 0} vectors for 4 inputs`);
} Type guard
import { isHttpEmbeddingError } from 'gitnexus';
const isCountMismatch = (e: unknown): boolean =>
isHttpEmbeddingError(e) &&
e instanceof Error &&
/vectors for \d+ texts/.test(e.message); Try / catch
try {
await httpEmbed(texts);
} catch (e) {
if (isHttpEmbeddingError(e) && /vectors for \d+ texts/.test(e.message)) {
// provider is truncating/dropping inputs; reduce load or pre-filter inputs
}
throw e;
} Prevention
- Check the provider's per-request input cap and ensure it is >= 64 (the client's batch size), or front with a splitting proxy.
- Pre-truncate over-long input texts so the provider does not silently drop them.
- Probe with a multi-input request before committing to a long run.
When it happens
Trigger: httpEmbedBatch's fetchImpl after shape validation: payload.data.length differs from batch.length. Concrete cases: endpoint silently drops inputs it deems too long and returns fewer vectors; endpoint has a hard input-count cap lower than HTTP_BATCH_SIZE (64) and truncates; truncated stream yields a partial array; empty `data: []` response.
Common situations: Provider limits inputs per request to fewer than 64 (GitNexus's batch size) and returns only the accepted ones. Some inputs exceed the provider's max token length and are dropped without error. Network truncation cuts the JSON mid-array. Provider returns [] for a rate-limited or filtered batch.
Related errors
- Embedding endpoint returned an unparseable response (${safeU
- Embedding endpoint returned an unexpected response shape (${
- ${err.terminalMessage}
- Embedding endpoint circuit open (${safeUrl(url)}, batch ${ba
- Embedding request timed out after ${timeoutMs}ms (${safeUrl(
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/9699084ca49e0012.
Report an issue: GitHub.