abhigyanpatwari/GitNexus · error · RetryableEmbeddingBodyError
Embedding endpoint returned
Error message
Embedding endpoint returned ${received} vectors for ${expected} texts (${safeEndpoint}, batch ${batchIndex}) What it means
httpEmbedBatch cardinality check (#2790): the endpoint returned 200 with validly-shaped payload.data but data.length !== batch.length — fewer (or more) vectors than input texts. A short body is treated as a truncated body: retried with the same backoff and breaker accounting as any endpoint fault, instead of being misclassified as success. Terminal only after retries exhaust.
Solutions
- Reduce the embedding batch size below the provider's documented maximum.
- Ensure no empty/whitespace-only texts are sent in a batch (filter before embedding).
- Check provider-side filtering (content policy, token limits) that drops individual inputs.
- Reproduce with curl sending the same N inputs and count returned items.
Example fix
// before
const batch = texts; // may exceed provider cap or contain ''
// after
const SAFE_BATCH = 32;
const batch = texts.filter((t) => t.trim().length > 0);
for (let i = 0; i < batch.length; i += SAFE_BATCH) { /* embed slice */ } Defensive patterns
Strategy: validation
Validate before calling
// pre-split batches under the provider cap and drop empty inputs const MAX_BATCH = 32; const clean = texts.filter((t) => typeof t === 'string' && t.trim().length > 0); const chunks = []; for (let i = 0; i < clean.length; i += MAX_BATCH) chunks.push(clean.slice(i, i + MAX_BATCH));
Type guard
const isCountMismatch = (e: unknown): boolean => e instanceof Error && /returned \d+ vectors for \d+ texts/.test(e.message);
Try / catch
try {
vectors = await httpEmbed(batch);
} catch (e) {
if (isCountMismatch(e)) {
const [got, want] = e.message.match(/(\d+) vectors for (\d+)/)!.slice(1).map(Number);
if (got < want) batch = batch.slice(0, got).length === got ? batch.slice(0, got) : batch; // shrink and re-embed remainder
} else throw e;
} Prevention
- Know your provider's max batch size and split inputs below it.
- Filter empty/whitespace strings before embedding — providers silently drop them.
- Watch for provider-side content filtering dropping individual inputs.
When it happens
Trigger: An endpoint that silently drops items — e.g. empty-string inputs filtered server-side, per-item content filtering, providers that cap batch size and truncate the response, or a half-serialized response under load.
Common situations: Batch size larger than the provider's limit (some return only the first N), inputs containing empty strings the provider skips, or a flaky server cutting responses mid-array.
Related errors
- Embedding endpoint circuit open
- Embedding endpoint returned an unexpected response shape
- Embedding endpoint returned an unparseable response
- Embedding endpoint returned
- Embedding request cancelled
AI-assisted analysis of abhigyanpatwari/GitNexus@ac9a4e9abd (2026-08-20).
Data as JSON: /api/errors/9699084ca49e0012.
Report an issue: GitHub.
Appendix: source
Thrown at gitnexus/src/core/embeddings/http-client.ts:522
// response" so they never reach for the timeout knob.
// Opt-in `GITNEXUS_EMBEDDING_RETRY_TIMEOUTS=1` is the exception:
// TimeoutError is re-wrapped so the existing retry loop can retry it.
throwIfRetryableTimeout(err, retryTimeouts, requestOptions.signal?.aborted, timeoutMs);
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 ac9a4e9abd)