tobi/qmd · error · Error

Provide either configPath or config, not both

Error message

Provide either configPath or config, not both

What it means

createStore accepts configuration either from a file (configPath) or an inline object (config), but not both — specifying both makes it ambiguous which one wins, so it rejects the call upfront.

Source

Thrown at src/index.ts:357

 * const store = await createStore({
 *   dbPath: './index.sqlite',
 *   config: {
 *     collections: {
 *       docs: { path: '/path/to/docs', pattern: '**\/*.md' }
 *     }
 *   }
 * })
 *
 * const results = await store.search({ query: "authentication flow" })
 * await store.close()
 * ```
 */
export async function createStore(options: StoreOptions): Promise<QMDStore> {
  if (!options.dbPath) {
    throw new Error("dbPath is required");
  }
  if (options.configPath && options.config) {
    throw new Error("Provide either configPath or config, not both");
  }

  // Create the internal store (opens DB, creates tables)
  const internal = createStoreInternal(options.dbPath);
  const db = internal.db;

  // Track whether we have a YAML config path for write-through
  const hasYamlConfig = !!options.configPath;

  // Sync config into SQLite store_collections
  let config: CollectionConfig | undefined;
  if (options.configPath) {
    // YAML mode: inject config source for write-through, sync to DB
    setConfigSource({ configPath: options.configPath });
    config = loadConfig();
    syncConfigToDb(db, config);
  } else if (options.config) {
    // Inline config mode: inject config source for mutations, sync to DB

View on GitHub (pinned to dbfd0b4736)

Solutions

  1. Pick one source: delete configPath if you have an inline config object, or drop config to load from file
  2. Load the file yourself once and merge into a single inline config object

Example fix

// before
await createStore({
  dbPath: './db.sqlite',
  configPath: './qmd.yaml',
  config: myConfig,
});
// after
await createStore({
  dbPath: './db.sqlite',
  config: myConfig,
});
Defensive patterns

Strategy: validation

Validate before calling

if (options.configPath && options.config) {
  delete options.configPath; // or merge: load file then deep-merge inline config
}

Type guard

const isExclusiveConfig = (o: StoreOptions): boolean =>
  !(o.configPath && o.config);

Prevention

When it happens

Trigger: Calling createStore({dbPath, configPath: './qmd.yaml', config: {collections: {...}}}) with both fields set.

Common situations: Layered app configs merging defaults (file) with overrides (inline object); copy-pasting examples that each used a different option; passing process.env-based config alongside a checked-in config path.

Related errors


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