abhigyanpatwari/GitNexus · error · HttpEmbeddingError

Embedding dimension mismatch: endpoint returned

Error message

Embedding dimension mismatch: endpoint returned ${vec.length}d vector, but expected ${expected}d. ${hint}

What it means

HttpEmbeddingError thrown during httpEmbed() when the endpoint returns a vector whose width differs from the expected width (config.dimensions from GITNEXUS_EMBEDDING_DIMS, defaulting to 384). This is deliberately terminal on first occurrence, not retried (#2790): a width mismatch is an operator configuration error, not a transient endpoint fault, and retrying cannot change the vector width. The message embeds the actual width and an actionable hint.

Solutions

  1. Read the number in the message and set it explicitly: export GITNEXUS_EMBEDDING_DIMS=<returned-width> (the hint line already contains the exact assignment).
  2. If GITNEXUS_EMBEDDING_DIMS was explicitly set to the wrong value, update it to match the model's actual output width.
  3. After changing dims, re-run the full analyze/embedding pass so stored vectors match the new width; mixing widths corrupts similarity search.
  4. If the server should honor a dimensions request but does not, verify with curl that the dimensions field is accepted, and use GITNEXUS_EMBEDDING_REQUEST_DIMS only for what is sent on the wire.

Example fix

# before
export GITNEXUS_EMBEDDING_MODEL=text-embedding-3-small   # returns 1536d
# GITNEXUS_EMBEDDING_DIMS unset -> expects default 384
gitnexus analyze  # -> Embedding dimension mismatch: endpoint returned 1536d vector, but expected 384d.

# after
export GITNEXUS_EMBEDDING_DIMS=1536
gitnexus analyze  # fresh index with 1536d vectors
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: embed one probe string and pin GITNEXUS_EMBEDDING_DIMS to the answer.
import { isHttpMode } from './core/embeddings/http-client.js';

export async function resolveEmbeddingDims(): Promise<number> {
  if (!isHttpMode()) return 0; // local embedder path
  const base = process.env.GITNEXUS_EMBEDDING_URL!.replace(/\/+$/, '');
  const res = await fetch(`${base}/embeddings`, {
    method: 'POST',
    headers: {
      'content-type': 'application/json',
      authorization: `Bearer ${process.env.GITNEXUS_EMBEDDING_API_KEY ?? 'unused'}`,
    },
    body: JSON.stringify({ model: process.env.GITNEXUS_EMBEDDING_MODEL, input: ['ping'] }),
  });
  if (!res.ok) throw new Error(`dims probe failed: ${res.status}`);
  const { data } = (await res.json()) as { data: { embedding: number[] }[] };
  return data[0].embedding.length;
}

Type guard

import { HttpEmbeddingError } from './core/embeddings/http-client.js';

export const isDimensionMismatchError = (e: unknown): e is HttpEmbeddingError =>
  e instanceof HttpEmbeddingError && e.message.startsWith('Embedding dimension mismatch');

Try / catch

try {
  vectors = await httpEmbed(texts);
} catch (err) {
  if (isDimensionMismatchError(err)) {
    // Terminal config error — do NOT retry; dims cannot change between calls.
    const actual = /returned (\d+)d/.exec(err.message)?.[1];
    throw new Error(
      `Model width changed. Re-run with GITNEXUS_EMBEDDING_DIMS=${actual} and rebuild the index`,
      { cause: err },
    );
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling httpEmbed() after switching the embedding model (e.g. from a 384-dim MiniLM model to a 768-dim or 1536-dim model) without updating GITNEXUS_EMBEDDING_DIMS; or explicitly setting GITNEXUS_EMBEDDING_DIMS=384 while pointing at a model that outputs another width; or a server that ignores the requested dimensions parameter.

Common situations: Swapping a local Ollama model for an OpenAI text-embedding-3-* model (1536/3072 dims) while the index and env still assume 384; a gateway silently substituting a different model version; re-using an old .env against a new endpoint. Note the vector width is baked into the existing index, so changing dims requires re-embedding.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@ac9a4e9abd (2026-08-20). Data as JSON: /api/errors/44f112d66ff16e38. Report an issue: GitHub.

Appendix: source

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

      // into the FLOAT[N] column which would cause a cryptic Kuzu error.
      //
      // Unlike the cardinality check this one stays *outside* the retry loop,
      // deliberately. The expected width is `config.dimensions ?? DEFAULT_DIMS`
      // (GITNEXUS_EMBEDDING_DIMS), which is NOT the `dimensions` value
      // `httpEmbedBatch` receives — that is `config.requestDimensions`, which
      // `GITNEXUS_EMBEDDING_REQUEST_DIMS` can set to a different number or to
      // `undefined` (`omit`). More importantly a width mismatch is an operator
      // *configuration* error, not an endpoint fault: retrying it three times
      // can never change the answer, and routing it through the retry loop
      // would count a healthy endpoint's responses toward the shared circuit
      // breaker. The message is an actionable config hint, so it is terminal
      // on the first attempt by design (#2790).
      const expected = config.dimensions ?? DEFAULT_DIMS;
      if (vec.length !== expected) {
        const hint = config.dimensions
          ? 'Update GITNEXUS_EMBEDDING_DIMS to match your model output.'
          : `Set GITNEXUS_EMBEDDING_DIMS=${vec.length} to match your model output.`;
        throw new HttpEmbeddingError(
          `Embedding dimension mismatch: endpoint returned ${vec.length}d vector, ` +
            `but expected ${expected}d. ${hint}`,
        );
      }

      allVectors.push(vec);
    }
  }

  return allVectors;
};

/**
 * Embed a single query text via the HTTP backend.
 * Convenience for MCP search where only one vector is needed.
 *
 * @param text - Query text to embed
 * @returns Embedding vector as number array

View on GitHub (pinned to ac9a4e9abd)