tobi/qmd · error · Error

Collection '${newName}' already exists

Error message

Collection '${newName}' already exists

What it means

renameStoreCollection() refuses to rename a collection to a name that already exists in the store_collections table, to avoid a name collision (which would otherwise break unique lookups).

Source

Thrown at src/store.ts:1380

    collection.path,
    collection.pattern || '**/*.md',
    collection.ignore ? JSON.stringify(collection.ignore) : null,
    collection.includeByDefault === false ? 0 : 1,
    collection.update || null,
    collection.context ? JSON.stringify(collection.context) : null,
  );
}

export function deleteStoreCollection(db: Database, name: string): boolean {
  const result = db.prepare(`DELETE FROM store_collections WHERE name = ?`).run(name);
  return result.changes > 0;
}

export function renameStoreCollection(db: Database, oldName: string, newName: string): boolean {
  // Check target doesn't exist
  const existing = db.prepare(`SELECT name FROM store_collections WHERE name = ?`).get(newName) as { name: string } | null | undefined;
  if (existing != null) {
    throw new Error(`Collection '${newName}' already exists`);
  }

  const result = db.prepare(`UPDATE store_collections SET name = ? WHERE name = ?`).run(newName, oldName);
  return result.changes > 0;
}

export function updateStoreContext(db: Database, collectionName: string, path: string, text: string): boolean {
  const row = db.prepare(`SELECT context FROM store_collections WHERE name = ?`).get(collectionName) as { context: string | null } | null | undefined;
  if (row == null) return false;

  const ctxMap: ContextMap = row.context ? JSON.parse(row.context) : {};
  ctxMap[path] = text;
  db.prepare(`UPDATE store_collections SET context = ? WHERE name = ?`).run(JSON.stringify(ctxMap), collectionName);
  return true;
}

export function removeStoreContext(db: Database, collectionName: string, path: string): boolean {
  const row = db.prepare(`SELECT context FROM store_collections WHERE name = ?`).get(collectionName) as { context: string | null } | null | undefined;

View on GitHub (pinned to dbfd0b4736)

Solutions

  1. Choose a different target name
  2. Delete or re-add the existing target collection first if the collision is intended (qmd collection remove <new>)
  3. Check collection existence with `qmd collection list` before renaming

Example fix

// before
renameStoreCollection(db, 'mynotes', 'notes'); // 'notes' exists
// after
if (!collectionExists(db, 'notes')) renameStoreCollection(db, 'mynotes', 'notes');
else throw new Error('target name taken — pick another');
Defensive patterns

Strategy: validation

Validate before calling

const exists = db.prepare('SELECT 1 FROM store_collections WHERE name=?').get(newName); if (!exists) renameStoreCollection(db, old, newName);

Type guard

const isNameFree = (db: Database, n: string) => db.prepare('SELECT 1 FROM store_collections WHERE name=?').get(n) == null;

Prevention

When it happens

Trigger: Calling renameStoreCollection(db, old, new) where a collection named `new` already exists — e.g. `qmd collection rename mynotes notes` when `notes` exists.

Common situations: Re-creating a target name after a previous merge/rename; case-insensitive filesystems hiding an existing name; scripts renaming in a loop that re-run after partial failure.

Related errors


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