abhigyanpatwari/GitNexus · error · HttpEmbeddingError
Embedding request failed
Error message
Embedding request failed (${safeUrl(url)}, batch ${batchIndex}): ${reason} What it means
Thrown as HttpEmbeddingError when a batched POST to <GITNEXUS_EMBEDDING_URL>/embeddings fails at the transport layer (DNS failure, connection refused, TLS error, timeout, or aborted request). resilientFetch has already exhausted its retry budget (5xx/429 with capped backoff), so this error means the endpoint could not be reached successfully at all. The reason string is sanitized (sanitizeReason strips API keys) and the URL is redacted via safeUrl, so the message is safe to log.
Solutions
- Verify the endpoint is reachable from the same machine: curl -sS -o /dev/null -w '%{http_code}' "$GITNEXUS_EMBEDDING_URL/embeddings" (expect 4xx, not 000).
- Check for typos in GITNEXUS_EMBEDDING_URL (no scheme, wrong port, trailing garbage); the code appends /embeddings itself, so supply only the base URL such as http://localhost:11434/v1.
- If behind a proxy or VPN, make sure HTTPS_PROXY/HTTP_PROXY or DNS resolution works for the embedding host, or start the local embedding server (e.g. ollama serve).
- For slow endpoints, raise the timeout env var and retry budget before concluding the host is down.
- If embeddings are optional, unset GITNEXUS_EMBEDDING_URL and GITNEXUS_EMBEDDING_MODEL to fall back to the local ONNX embedder instead of the HTTP backend.
Example fix
# before export GITNEXUS_EMBEDDING_URL=http://locahost:11434/v1 # typo: locahost export GITNEXUS_EMBEDDING_MODEL=nomic-embed-text gitnexus analyze # -> Embedding request failed (http://locahost..., batch 0): ... # after export GITNEXUS_EMBEDDING_URL=http://localhost:11434/v1 gitnexus analyze
Defensive patterns
Strategy: try-catch
Validate before calling
// Fail fast before a long analyze run: probe the embedding endpoint.
import { isHttpMode } from './core/embeddings/http-client.js';
export async function assertEmbeddingEndpointReachable(): Promise<void> {
if (!isHttpMode()) return;
const base = process.env.GITNEXUS_EMBEDDING_URL!.replace(/\/+$/, '');
const res = await fetch(`${base}/embeddings`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
model: process.env.GITNEXUS_EMBEDDING_MODEL,
input: ['ping'],
}),
signal: AbortSignal.timeout(10_000),
}).catch((err) => {
throw new Error(`embedding endpoint unreachable: ${base} (${err.message})`);
});
if (res.status >= 500 || res.status === 429) {
throw new Error(`embedding endpoint unhealthy: ${res.status}`);
}
} Type guard
import { HttpEmbeddingError } from './core/embeddings/http-client.js';
export const isHttpEmbeddingError = (e: unknown): e is HttpEmbeddingError =>
e instanceof HttpEmbeddingError; Try / catch
try {
vectors = await httpEmbed(texts);
} catch (err) {
if (isHttpEmbeddingError(err) && err.message.startsWith('Embedding request failed')) {
// Transport-level failure; internal retries already exhausted by resilientFetch.
// Log sanitized message (URL/api key already redacted) and surface a fix hint.
throw new Error(
`${err.message} — check GITNEXUS_EMBEDDING_URL reachability, proxy/DNS, ` +
'and GITNEXUS_EMBEDDING_TIMEOUT_MS',
{ cause: err },
);
}
throw err;
} Prevention
- Verify the endpoint with a one-line curl POST to $GITNEXUS_EMBEDDING_URL/embeddings before starting analyze.
- Run a reachability probe (like the validationCode above) at pipeline startup so a dead endpoint fails in seconds, not mid-batch.
- For local servers (Ollama, vLLM), add a healthcheck to the wrapper script that starts them before gitnexus.
- Keep GITNEXUS_EMBEDDING_MAX_ATTEMPTS and the timeout env vars sized for your endpoint's latency to survive transient blips.
When it happens
Trigger: Calling httpEmbed() or httpEmbedBatch() while GITNEXUS_EMBEDDING_URL points to an unreachable host (typo in hostname, DNS not resolving), the embedding server is down, a proxy/firewall blocks the egress, the TLS certificate is invalid, or the per-request timeout (GITNEXUS_EMBEDDING_TIMEOUT_MS) is exceeded on every attempt. Also triggered when GITNEXUS_EMBEDDING_MAX_ATTEMPTS retries are all consumed by network resets.
Common situations: Running `gitnexus analyze` on a laptop with a corporate proxy that intercepts HTTPS; pointing GITNEXUS_EMBEDDING_URL at a localhost Ollama/LM Studio instance that is not started; using an internal DNS name that only resolves inside the VPN; a self-signed certificate on a private vLLM endpoint.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- Embedding endpoint returned
- after attempt(s) ( , batch )
- err.terminalMessage (terminal 2xx body error)
- must be a positive integer, got
- must be a positive integer <= , got
AI-assisted analysis of abhigyanpatwari/GitNexus@ac9a4e9abd (2026-08-20).
Data as JSON: /api/errors/b750d553eaf69212.
Report an issue: GitHub.
Appendix: source
Thrown at gitnexus/src/core/embeddings/http-client.ts:582
{ 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 },
);
}
if (err instanceof ResilientFetchExhaustedError) {
throw new HttpEmbeddingError(
`Embedding endpoint returned ${err.response.status} (${safeUrl(url)}, batch ${batchIndex})`,
{ cause: err },
);
}
const reason = sanitizeReason(err instanceof Error ? err.message : String(err), url, apiKey);
const safeCause = new Error(reason);
safeCause.name = err instanceof Error ? err.name : 'EmbeddingTransportError';
throw new HttpEmbeddingError(
`Embedding request failed (${safeUrl(url)}, batch ${batchIndex}): ${reason}`,
{ cause: safeCause },
);
}
if (!resp.ok) {
// resilientFetch already retried 5xx/429; any non-OK response here is
// a terminal client error (4xx other than 429).
throw new HttpEmbeddingError(
`Embedding endpoint returned ${resp.status} (${safeUrl(url)}, batch ${batchIndex})`,
);
}
if (parsed === undefined) {
// Defensively unreachable: an OK response either sets `parsed` or throws
// out of `fetchImpl`. Kept so the narrowing holds without a non-null
// assertion, and so a future `resilientFetch` change can't return an
// unvalidated body silently.View on GitHub (pinned to ac9a4e9abd)