actualbudget/actual · error · Error
--where and --filter are mutually exclusive
Error message
--where and --filter are mutually exclusive
What it means
The Actual CLI's `actual query` command lets you build an AQL query either inline with --where/--select flags or via a structured --filter expression. These two filtering mechanisms are mutually exclusive, so buildQueryFromFlags throws when both --where and --filter are supplied on the same invocation. It is an early validation guard before any query is executed against the budget.
Source
Thrown at packages/cli/src/commands/query.ts:172
if (cmdOpts.limit) {
throw new Error('--last and --limit are mutually exclusive');
}
}
const table =
cmdOpts.table ?? (last !== undefined ? 'transactions' : undefined);
if (!table) {
throw new Error('--table is required (or use --file or --last)');
}
if (!(table in TABLE_SCHEMA)) {
throw new Error(
`Unknown table "${table}". Available tables: ${AVAILABLE_TABLES}`,
);
}
if (cmdOpts.where && cmdOpts.filter) {
throw new Error('--where and --filter are mutually exclusive');
}
if (cmdOpts.count && cmdOpts.select) {
throw new Error('--count and --select are mutually exclusive');
}
let queryObj = api.q(table);
if (cmdOpts.count) {
queryObj = queryObj.calculate({ $count: '*' });
} else if (cmdOpts.select) {
queryObj = queryObj.select(cmdOpts.select.split(','));
} else if (last !== undefined) {
queryObj = queryObj.select(LAST_DEFAULT_SELECT);
}
const filterStr = cmdOpts.filter ?? cmdOpts.where;
if (filterStr) {View on GitHub (pinned to d4334cb6e6)
Solutions
- Remove the --where flag and express the condition inside --filter, or vice versa
- Convert the --where expression into the equivalent AQL filter JSON: e.g. --where 'amount>0' becomes --filter '{"amount":{"$gt":0}}'
- If a wrapper script sets --filter, drop your manual --where or edit the wrapper
Example fix
// before
actual query transactions --where "amount>0" --filter '{"date":{"$gte":"2024-01-01"}}'
// after (merge into one filter)
actual query transactions --filter '{"$and":[{"amount":{"$gt":0}},{"date":{"$gte":"2024-01-01"}}]}' Defensive patterns
Strategy: validation
Validate before calling
// in the script that assembles CLI args
const args = ['query', 'transactions'];
if (whereExpr) args.push('--where', whereExpr);
if (filterJson) args.push('--filter', filterJson);
if (whereExpr && filterJson) {
throw new Error('Pass either --where or --filter, not both');
} Type guard
function hasExclusiveFlags(opts: { where?: string; filter?: string }): boolean {
return opts.where !== undefined && opts.filter !== undefined;
} Try / catch
try {
await run(['actual', 'query', 'transactions', ...flags]);
} catch (e) {
if (String(e.message).includes('mutually exclusive')) {
console.error('Drop either --where or --filter');
} else throw e;
} Prevention
- Pick one filtering style (--filter for structured AQL, --where for quick expressions) and standardize scripts on it
- Keep flag assembly in one helper so conflicting flags can't accumulate
- Wrap --filter JSON in '$and' when merging conditions instead of adding --where
When it happens
Trigger: Running `actual query transactions --where 'amount>0' --filter '{"date":{"$gte":"2024-01-01"}}'` — both flags set on the same command. Also happens in scripts that pass flags conditionally (e.g. a wrapper always appends --filter while the user also passes --where).
Common situations: Users combining examples from different docs pages; shell scripts accumulating flags from multiple config sources; copy-pasting a filter expression into an existing command that already had a --where clause.
Related errors
- --count and --select are mutually exclusive
- Query file must contain a JSON object
- Query result missing data
- Unknown table "${table}". Available tables: ${Object.keys(TA
- At least one of --tag, --color, or --description is required
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/537b37a99277f8c3.
Report an issue: GitHub.