{"record":{"id":"021c57ece9f752bb","repo":"abhigyanpatwari/GitNexus","slug":"cannot-resume-embedding-checkpoint-the-embedding","errorCode":null,"errorMessage":"Cannot resume embedding checkpoint: the embedding provider configuration differs. Restore the matching endpoint configuration or pass --drop-embeddings to rebuild without it.","messagePattern":"Cannot resume embedding checkpoint: the embedding provider configuration differs\\. Restore the matching endpoint configuration or pass --drop-embeddings to rebuild without it\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/run-analyze.ts","lineNumber":1315,"sourceCode":"  let resumedEmbeddingCheckpoint: EmbeddingCheckpoint | undefined;\n  if (existingMeta?.embeddingCheckpoint) {\n    const checkpoint = existingMeta.embeddingCheckpoint;\n    // The verdict itself lives in embedding-checkpoint.ts, shared with\n    // `POST /api/embed` — two readers of one marker must not be able to\n    // disagree about what it means.\n    //\n    // The identity stays LAZY, as it has to: the flag and retry-budget verdicts\n    // short-circuit before one is needed, and resolving it means importing an\n    // embeddings module (#2370 — none loads unless a run actually needs one).\n    // `decideEmbeddingResume` asks for it by aborting on `undefined`, which is\n    // the only abort it can reach without one.\n    let decision = decideEmbeddingResume(checkpoint, undefined, options);\n    if (decision.action === 'abort') {\n      const { resolveEmbeddingIdentity } = await import('./embeddings/embedding-identity.js');\n      embeddingIdentityForRun = resolveEmbeddingIdentity();\n      decision = decideEmbeddingResume(checkpoint, embeddingIdentityForRun, options);\n    }\n    if (decision.action === 'abort') throw new Error(decision.error);\n    log(decision.log);\n    if (options.dropEmbeddings) {\n      // --drop-embeddings has always implied a rebuild here; the decision only\n      // covers the marker.\n      options = { ...options, force: true };\n    }\n    if (decision.action === 'resume') {\n      resumeEmbeddingCheckpoint = true;\n      pendingEmbeddingNodeIds = new Set(decision.pendingNodeIds);\n      resumedEmbeddingCheckpoint = decision.resumedFrom;\n    }\n  }\n\n  // ── Crash recovery: dirty flag forces full rebuild ────────────────\n  // If the previous incremental run set incrementalInProgress and didn't\n  // clear it, the on-disk index may be in a half-state. Cheapest path\n  // back to a known-good index is to wipe + rebuild from scratch.\n  if (existingMeta?.incrementalInProgress) {","sourceCodeStart":1297,"sourceCodeEnd":1333,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/gitnexus/src/core/run-analyze.ts#L1297-L1333","documentation":"Thrown by `decideEmbeddingResume` when the checkpoint's `provider` field differs from the current run's resolved provider AND the checkpoint kind is `'interrupted'`. An 'interrupted' marker means its pending nodes may hold a subset of their chunks, so resuming under a different provider would mix two embedding vector spaces — a silent semantic-search corruption. The function fails closed rather than risk the mix.","triggerScenarios":"`decideEmbeddingResume` is called with a resolved `identity` where `checkpoint.provider !== identity.provider`, the checkpoint kind is `'interrupted'`, and neither `--force` nor `--drop-embeddings` was passed (both short-circuit earlier).","commonSituations":"A team member indexed with an OpenAI embedding endpoint, left an interrupted checkpoint, then a colleague's environment points to a local Ollama provider; or the endpoint URL env var was changed between runs without `--drop-embeddings`.","solutions":["Restore the original embedding provider configuration (`GITNEXUS_EMBEDDING_URL` and related provider env vars) to match the checkpoint, then re-run `gitnexus analyze`.","If the provider change is intentional, run `gitnexus analyze --drop-embeddings` to discard the old checkpoint and rebuild under the new provider.","Run `gitnexus analyze --force` for a full rebuild (this also discards the checkpoint)."],"exampleFix":"// before\n// checkpoint provider=openai, current run provider=ollama\ngitnexus analyze\n// error: ...embedding provider configuration differs.\n// after (intentional switch)\ngitnexus analyze --drop-embeddings\n// or (restore original)\nexport GITNEXUS_EMBEDDING_URL=https://api.openai.com/v1\ngitnexus analyze","handlingStrategy":"validation","validationCode":"// Before analyze, compare checkpoint provider with current env:\nimport { loadMeta } from './storage/repo-manager.js';\nimport { checkpointKind } from './embedding-checkpoint.js';\nconst meta = await loadMeta(metaDir);\nconst cp = meta?.embeddingCheckpoint;\nif (cp && checkpointKind(cp) === 'interrupted') {\n  const currentProvider = process.env.GITNEXUS_EMBEDDING_PROVIDER ?? deriveProviderFromUrl(process.env.GITNEXUS_EMBEDDING_URL);\n  if (currentProvider && cp.provider !== currentProvider) {\n    console.error(`Provider mismatch: checkpoint=${cp.provider}, current=${currentProvider}.`);\n    console.error('Restore matching config or pass --drop-embeddings.');\n    process.exit(1);\n  }\n}","typeGuard":"import { checkpointKind } from './embedding-checkpoint.js';\nconst isProviderMismatchFatal = (\n  checkpoint: EmbeddingCheckpoint,\n  currentProvider: string,\n): boolean =>\n  checkpointKind(checkpoint) === 'interrupted' &&\n  checkpoint.provider !== currentProvider;","tryCatchPattern":"try {\n  await runAnalyze(options);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('embedding provider configuration differs')) {\n    console.error('Restore the original provider config or run `gitnexus analyze --drop-embeddings`.');\n  }\n  throw err;\n}","preventionTips":["Pin embedding provider configuration in a `.gitnexusrc` or consistent CI env to avoid accidental provider switches.","When switching providers intentionally, always pass `--drop-embeddings`."],"tags":["embeddings","checkpoint","resume","configuration","provider-mismatch"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}