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 DBView on GitHub (pinned to dbfd0b4736)
Solutions
- Pick one source: delete configPath if you have an inline config object, or drop config to load from file
- 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
- Pick one config source per project and stick to it
- If merging file + overrides is needed, load and merge yourself, pass only `config`
- Use TypeScript's discriminated unions or a lint rule against passing both keys
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
- dbPath is required
- search() requires either 'query' or 'queries'
- Line ${line.number} is missing a lex:/vec:/hyde:/intent: pre
- intent: cannot appear alone. Add at least one lex:, vec:, or
- Invalid expandContextSize: ${configValue}. Must be a positiv
AI-assisted analysis of tobi/qmd@dbfd0b4736 (2026-08-28).
Data as JSON: /api/errors/df7bd7b136794543.
Report an issue: GitHub.