abhigyanpatwari/GitNexus · error · Error
Cannot resume embedding checkpoint: it uses ${checkpoint.mod
Error message
Cannot resume embedding checkpoint: it uses ${checkpoint.model} at ${checkpoint.dimensions} dimensions, but this run resolves ${identity.model} at ${identity.dimensions}. Restore the matching embedding configuration or pass --drop-embeddings to rebuild without it. What it means
Thrown by `decideEmbeddingResume` when the checkpoint's model or dimensions differ from the current run's resolved identity (provider matches), and the checkpoint kind is `'interrupted'`. Even with the same provider, a different model or dimensionality produces incompatible vectors — resuming would write rows into a vector space that doesn't match the existing ones, corrupting semantic search.
Source
Thrown at gitnexus/src/core/run-analyze.ts:1315
let resumedEmbeddingCheckpoint: EmbeddingCheckpoint | undefined;
if (existingMeta?.embeddingCheckpoint) {
const checkpoint = existingMeta.embeddingCheckpoint;
// The verdict itself lives in embedding-checkpoint.ts, shared with
// `POST /api/embed` — two readers of one marker must not be able to
// disagree about what it means.
//
// The identity stays LAZY, as it has to: the flag and retry-budget verdicts
// short-circuit before one is needed, and resolving it means importing an
// embeddings module (#2370 — none loads unless a run actually needs one).
// `decideEmbeddingResume` asks for it by aborting on `undefined`, which is
// the only abort it can reach without one.
let decision = decideEmbeddingResume(checkpoint, undefined, options);
if (decision.action === 'abort') {
const { resolveEmbeddingIdentity } = await import('./embeddings/embedding-identity.js');
embeddingIdentityForRun = resolveEmbeddingIdentity();
decision = decideEmbeddingResume(checkpoint, embeddingIdentityForRun, options);
}
if (decision.action === 'abort') throw new Error(decision.error);
log(decision.log);
if (options.dropEmbeddings) {
// --drop-embeddings has always implied a rebuild here; the decision only
// covers the marker.
options = { ...options, force: true };
}
if (decision.action === 'resume') {
resumeEmbeddingCheckpoint = true;
pendingEmbeddingNodeIds = new Set(decision.pendingNodeIds);
resumedEmbeddingCheckpoint = decision.resumedFrom;
}
}
// ── Crash recovery: dirty flag forces full rebuild ────────────────
// If the previous incremental run set incrementalInProgress and didn't
// clear it, the on-disk index may be in a half-state. Cheapest path
// back to a known-good index is to wipe + rebuild from scratch.
if (existingMeta?.incrementalInProgress) {View on GitHub (pinned to d540b00184)
Solutions
- Restore the original `GITNEXUS_EMBEDDING_MODEL` (and any dimension-affecting config) to match the checkpoint, then re-run `gitnexus analyze`.
- If the model change is intentional, run `gitnexus analyze --drop-embeddings` to discard the old checkpoint and rebuild under the new model.
- Run `gitnexus analyze --force` for a full rebuild.
Example fix
// before // checkpoint model=text-embedding-ada-002, current model=text-embedding-3-small gitnexus analyze // error: ...uses text-embedding-ada-002 at 1536 dimensions, but this run resolves... // after (intentional model upgrade) gitnexus analyze --drop-embeddings
Defensive patterns
Strategy: validation
Validate before calling
// Before analyze, compare checkpoint model/dimensions with current env:
import { loadMeta } from './storage/repo-manager.js';
import { checkpointKind } from './embedding-checkpoint.js';
const meta = await loadMeta(metaDir);
const cp = meta?.embeddingCheckpoint;
if (cp && checkpointKind(cp) === 'interrupted') {
const currentModel = process.env.GITNEXUS_EMBEDDING_MODEL;
if (currentModel && cp.model !== currentModel) {
console.error(`Model mismatch: checkpoint=${cp.model}, current=${currentModel}.`);
console.error('Restore matching config or pass --drop-embeddings.');
process.exit(1);
}
} Type guard
import { checkpointKind } from './embedding-checkpoint.js';
const isModelMismatchFatal = (
checkpoint: EmbeddingCheckpoint,
currentModel: string,
currentDims: number,
): boolean =>
checkpointKind(checkpoint) === 'interrupted' &&
(checkpoint.model !== currentModel || checkpoint.dimensions !== currentDims); Try / catch
try {
await runAnalyze(options);
} catch (err) {
if (err instanceof Error && err.message.includes('it uses') && err.message.includes('dimensions')) {
console.error('Restore the original embedding model or run `gitnexus analyze --drop-embeddings`.');
}
throw err;
} Prevention
- Pin `GITNEXUS_EMBEDDING_MODEL` in config to avoid silent model drift across environments.
- When upgrading embedding models, always pass `--drop-embeddings` to avoid vector-space incompatibility.
When it happens
Trigger: `decideEmbeddingResume` with a resolved identity where `checkpoint.model !== identity.model` or `checkpoint.dimensions !== identity.dimensions` (provider matches), kind is `'interrupted'`, and no `--force`/`--drop-embeddings` flag.
Common situations: Switched from `text-embedding-3-small` (1536 dims) to `text-embedding-3-large` (3072 dims) under the same OpenAI provider, or changed `GITNEXUS_EMBEDDING_MODEL` between runs, leaving an interrupted checkpoint from the old model.
Related errors
- Cannot resume embedding checkpoint: no embedding identity wa
- Cannot resume embedding checkpoint: the embedding provider c
- GITNEXUS_EMBEDDING_DIMS must be a positive integer, got "${p
- Embedding generation completed without persisted embeddings.
- ${source} must be true/false or a non-negative integer (node
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/3d32e65ae0ce1775.
Report an issue: GitHub.