tobi/qmd · critical · Error

Embedding dimension mismatch: existing vectors are ${existin

Error message

Embedding dimension mismatch: existing vectors are ${existingDims}d but the current model produces ${dimensions}d. Run 'qmd embed -f' to re-embed with the new model.

What it means

ensureVecTable() detected that the existing sqlite-vec virtual table `vectors_vec` was built with a different embedding dimensionality than the current embedding model produces. Vectors of differing dimensions cannot coexist, so the store aborts instead of silently corrupting search.

Source

Thrown at src/store.ts:1478

export function isSqliteVecAvailable(): boolean {
  return _sqliteVecAvailable === true;
}

function ensureVecTableInternal(db: Database, dimensions: number): void {
  if (!_sqliteVecAvailable) {
    throw createSqliteVecUnavailableError(
      _sqliteVecUnavailableReason ?? "vector operations require a SQLite build with extension loading support"
    );
  }
  const tableInfo = db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='vectors_vec'`).get() as { sql: string } | null;
  if (tableInfo) {
    const match = tableInfo.sql.match(/float\[(\d+)\]/);
    const hasHashSeq = tableInfo.sql.includes('hash_seq');
    const hasCosine = tableInfo.sql.includes('distance_metric=cosine');
    const existingDims = match?.[1] ? parseInt(match[1], 10) : null;
    if (existingDims === dimensions && hasHashSeq && hasCosine) return;
    if (existingDims !== null && existingDims !== dimensions) {
      throw new Error(
        `Embedding dimension mismatch: existing vectors are ${existingDims}d but the current model produces ${dimensions}d. ` +
        `Run 'qmd embed -f' to re-embed with the new model.`
      );
    }
    db.exec("DROP TABLE IF EXISTS vectors_vec");
  }
  db.exec(`CREATE VIRTUAL TABLE vectors_vec USING vec0(hash_seq TEXT PRIMARY KEY, embedding float[${dimensions}] distance_metric=cosine)`);
}

// =============================================================================
// Store Factory
// =============================================================================

export type Store = {
  db: Database;
  dbPath: string;
  /** Optional LlamaCpp instance for this store (overrides the global singleton) */
  llm?: LlamaCpp;

View on GitHub (pinned to dbfd0b4736)

Solutions

  1. Run `qmd embed -f` to force re-embedding everything with the current model
  2. Or delete/recreate the index (remove ~/.cache/qmd/index.sqlite or the collection) and re-index
  3. Keep one index per embedding model; re-embed immediately after any model change

Example fix

# before
qmd embed   # throws: dimension mismatch
# after
qmd embed -f   # re-embed all chunks with current model
Defensive patterns

Strategy: fallback

Validate before calling

// before embedding, compare dims:
const info = db.prepare("SELECT sql FROM sqlite_master WHERE name='vectors_vec'").get();
const dims = info?.sql?.match(/float\[(\d+)\]/)?.[1];
if (dims && +dims !== modelDims) await forceReembed();

Try / catch

try { store.ensureVecTable(dims); } catch (e) { if (/dimension mismatch/.test((e as Error).message)) { await runEmbedForce(); return; } throw e; }

Prevention

When it happens

Trigger: Switching embedding models (e.g. to embeddinggemma with a different dim count) and then embedding into an existing index whose vectors_vec table declares float[oldDims]; detected via the table DDL's float[N] match.

Common situations: Upgrading qmd to a version bundling a new embedding model; pointing qmd at an old index.sqlite created with a previous model; experimentation with custom GGUF embedding models.

Related errors


AI-assisted analysis of tobi/qmd@dbfd0b4736 (2026-08-28). Data as JSON: /api/errors/fcff097427145c26. Report an issue: GitHub.