abhigyanpatwari/GitNexus · error · HttpEmbeddingError

Embedding dimension mismatch: endpoint returned ${vec.length

Error message

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

What it means

An HttpEmbeddingError thrown by httpEmbed when an embedding vector's width does not match the expected dimension (config.dimensions ?? DEFAULT_DIMS, i.e. GITNEXUS_EMBEDDING_DIMS or 384). It is thrown outside the retry loop deliberately: a width mismatch is an operator configuration error, not an endpoint fault, so retrying cannot change the answer and routing it through the retry loop would unfairly penalize a healthy endpoint via the shared circuit breaker (#2790). The message names both widths and emits an actionable config hint.

Source

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

      // 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 d540b00184)

Solutions

  1. If GITNEXUS_EMBEDDING_DIMS is set: update it to match the returned width shown in the message (e.g. the endpoint returned 1536d → set GITNEXUS_EMBEDDING_DIMS=1536).
  2. If GITNEXUS_EMBEDDING_DIMS is unset: the message hint tells you exactly what to set, e.g. `Set GITNEXUS_EMBEDDING_DIMS=<returned> to match your model output`.
  3. If you requested truncation (GITNEXUS_EMBEDDING_REQUEST_DIMS=N), set GITNEXUS_EMBEDDING_DIMS=N too, since the returned width should equal the requested width.
  4. Re-index from scratch after changing dimensions — existing FLOAT[N] vectors are not auto-migrated.

Example fix

// before: using text-embedding-3-small (1536d) with default expected width
# GITNEXUS_EMBEDDING_DIMS unset → expects 384

// after
export GITNEXUS_EMBEDDING_DIMS=1536
Defensive patterns

Strategy: validation

Validate before calling

// After a model switch, confirm the declared width matches actual output:
const r = await fetch(`${URL}/embeddings`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${KEY}` }, body: JSON.stringify({ model: MODEL, input: 'probe' }) });
const j = await r.json();
const actual = j.data?.[0]?.embedding?.length;
const declared = parseInt(process.env.GITNEXUS_EMBEDDING_DIMS ?? '384', 10);
if (actual && actual !== declared) {
  throw new Error(`Dimension mismatch: model returns ${actual}d but DIMS declares ${declared}`);
}

Type guard

import { isHttpEmbeddingError } from 'gitnexus';
const isDimensionMismatch = (e: unknown): boolean =>
  isHttpEmbeddingError(e) && e instanceof Error && e.message.startsWith('Embedding dimension mismatch');

Try / catch

try {
  await httpEmbed(texts);
} catch (e) {
  if (isDimensionMismatch(e)) {
    // message hint says exactly what to set; update GITNEXUS_EMBEDDING_DIMS and re-index
  }
  throw e;
}

Prevention

When it happens

Trigger: httpEmbed after httpEmbedBatch returns well-shaped items: new Float32Array(item.embedding).length !== (config.dimensions ?? 384). The endpoint's actual vector width disagrees with the declared/expected width. Common when GITNEXUS_EMBEDDING_DIMS is unset (default 384) but the model returns a different width, or when GITNEXUS_EMBEDDING_DIMS is set to a stale value after switching models.

Common situations: Switched from a 384d model to a 1536d model without updating GITNEXUS_EMBEDDING_DIMS. Left GITNEXUS_EMBEDDING_DIMS unset while using a non-384d model (default assumption is 384). Requested truncation via GITNEXUS_EMBEDDING_REQUEST_DIMS but forgot to set GITNEXUS_EMBEDDING_DIMS to the truncated width. Provider silently changed the model's output dimension.

Related errors


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