abhigyanpatwari/GitNexus · error · Error

Embedding generation completed without persisted embeddings.

Error message

Embedding generation completed without persisted embeddings. The index was not registered to avoid silently reporting embeddings: 0. Check the embedding endpoint/model configuration (GITNEXUS_EMBEDDING_URL / GITNEXUS_EMBEDDING_MODEL) and re-run `gitnexus analyze --embeddings`; the graph itself is unaffected, so `--drop-embeddings` indexes without them.

What it means

Thrown at the Phase 5 embedding gate when the embedding pipeline processed nodes (`attemptedEmbedding` is true: `nodesProcessed > 0` or `failedNodeIds.length > 0`), the graph has nodes (`stats.nodes > 0`), but the persisted embedding count is exactly zero. This is case (4) of four formerly-collapsed states: the pipeline ran and wrote nothing — a genuine defect, not a skip, an empty table, or a count-query failure. The index is deliberately not registered to avoid silently reporting `embeddings: 0`.

Source

Thrown at gitnexus/src/core/run-analyze.ts:3333

    //   1. the pipeline never ran (cap-skipped / not requested) —
    //      `embeddingSkipped`, still short-circuited;
    //   2. the pipeline ran but had NOTHING to embed (totalNodes 0 after the
    //      incremental filter — e.g. a resume whose pending sweep deleted the
    //      last rows) over a legitimately empty table;
    //   3. the count query failed or answered non-numerically (above) — a
    //      diagnostic failure, not an indexing failure;
    //   4. the pipeline embedded and NOTHING persisted — the real defect.
    // Only (4) throws. `attemptedEmbedding` is what separates it from (2):
    // `nodesProcessed` is now the REAL completed-node count and
    // `failedNodeIds` names the nodes whose rows were dropped, so
    // "attempted" ≡ at least one node was walked to a conclusion.
    const attemptedEmbedding =
      !embeddingSkipped &&
      embeddingResult !== undefined &&
      (embeddingResult.nodesProcessed > 0 || embeddingResult.failedNodeIds.length > 0);

    if (attemptedEmbedding && stats.nodes > 0 && embeddingCount === 0) {
      throw new Error(
        'Embedding generation completed without persisted embeddings. ' +
          'The index was not registered to avoid silently reporting embeddings: 0. ' +
          'Check the embedding endpoint/model configuration (GITNEXUS_EMBEDDING_URL / ' +
          'GITNEXUS_EMBEDDING_MODEL) and re-run `gitnexus analyze --embeddings`; ' +
          'the graph itself is unaffected, so `--drop-embeddings` indexes without them.',
      );
    }

    if (embeddingCount === undefined) {
      log(
        'Warning: registering the index without a verified embedding count — the count query ' +
          'did not answer, so stats.embeddings falls back to the last known value. ' +
          'Re-run `gitnexus analyze --embeddings` if semantic search comes back empty.',
      );
    }

    // ── An unverifiable count must leave a way back (#2790) ───────────────
    // The carry-forward below is a GUESS, and the guess is load-bearing (see

View on GitHub (pinned to d540b00184)

Solutions

  1. Verify `GITNEXUS_EMBEDDING_URL` points to the correct embeddings endpoint (e.g., `https://api.openai.com/v1/embeddings`, not `/v1/chat/completions`).
  2. Verify `GITNEXUS_EMBEDDING_MODEL` is a valid embedding model name for your provider.
  3. Test the endpoint manually with `curl` to confirm it returns embedding vectors for a sample input.
  4. Re-run `gitnexus analyze --embeddings` once the configuration is fixed.
  5. If you need the index without embeddings for now, run `gitnexus analyze --drop-embeddings` (the graph itself is unaffected).

Example fix

// before
export GITNEXUS_EMBEDDING_URL=https://api.openai.com/v1/chat/completions  # wrong endpoint
gitnexus analyze --embeddings
// error: Embedding generation completed without persisted embeddings.
// after
export GITNEXUS_EMBEDDING_URL=https://api.openai.com/v1/embeddings  # correct endpoint
gitnexus analyze --embeddings
Defensive patterns

Strategy: validation

Validate before calling

// Before analyze --embeddings, verify the endpoint returns vectors:
// (Quick smoke test of the embedding endpoint)
import { validateEmbeddingEndpoint } from './embeddings/endpoint-check.js';
const ok = await validateEmbeddingEndpoint(
  process.env.GITNEXUS_EMBEDDING_URL!,
  process.env.GITNEXUS_EMBEDDING_MODEL!,
);
if (!ok) {
  console.error('Embedding endpoint did not return valid vectors. Check URL and MODEL.');
  process.exit(1);
}

Type guard

const isLikelyEmbeddingsEndpoint = (url: string): boolean =>
  /\/embeddings?$/.test(url) || /embedding/i.test(url);

Try / catch

try {
  await runAnalyze({ ...options, embeddings: true });
} catch (err) {
  if (err instanceof Error && err.message.includes('completed without persisted embeddings')) {
    console.error('Check GITNEXUS_EMBEDDING_URL and GITNEXUS_EMBEDDING_MODEL. Test with curl first.');
    console.error('Run `gitnexus analyze --drop-embeddings` to index without embeddings for now.');
  }
  throw err;
}

Prevention

When it happens

Trigger: `attemptedEmbedding && stats.nodes > 0 && embeddingCount === 0`. The embedding endpoint accepted requests (or returned structured failures) but no rows were persisted to the embedding table. Typically the endpoint URL is wrong (200 HTML from a reverse proxy instead of an embedding API), the model name is invalid (endpoint returns an error for every node), or the embedding write path silently dropped all rows.

Common situations: `GITNEXUS_EMBEDDING_URL` points to a base URL that isn't an embeddings endpoint (e.g., points to the chat completions endpoint, or a login page); `GITNEXUS_EMBEDDING_MODEL` is not a valid model for the provider; the endpoint returns vectors in an unexpected format that the adapter rejects for every node; a network proxy strips or mangles the response body.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12). Data as JSON: /api/errors/6c1ba5c3fc16e974. Report an issue: GitHub.