krisk/Fuse · error · Error
Invalid field query for key '${key}': ${reason}
Error message
Invalid field query for key '${key}': ${reason} What it means
compileClause compiles an extended-search field clause into matchers and requires the clause to be a plain operator object (no top-level $and/$or). If the clause is not a plain object (string, array, number, null), it throws INVALID_FIELD_QUERY with the key path and reason 'each clause must be an operator object'.
Source
Thrown at src/search/extended/objectQuery.ts:41
// Anything deeper, structural siblings, empty objects/arrays, unknown operators,
// non-string or empty (post-normalization) values throw.
//
// Negation is `$not` wrapping exactly one operator, e.g. { $not: { $contains } }.
// It sits alongside other operators in a clause (they AND together) and resolves
// to the corresponding inverse matcher.
const AND = '$and'
const OR = '$or'
const NOT = '$not'
function isPlainObject(value: unknown): boolean {
return isObjectLike(value) && !isArray(value)
}
// Compile an operator-only object (no `$and`/`$or`) into one AND group.
function compileClause(clause: any, keyPath: string, options: any): Matcher[] {
if (!isPlainObject(clause)) {
throw new Error(
ErrorMsg.INVALID_FIELD_QUERY(
keyPath,
'each clause must be an operator object'
)
)
}
const ops = Object.keys(clause)
if (!ops.length) {
throw new Error(ErrorMsg.INVALID_FIELD_QUERY(keyPath, 'empty query'))
}
const group: Matcher[] = []
for (let i = 0; i < ops.length; i += 1) {
const op = ops[i]
if (op === AND || op === OR) {
throw new Error(View on GitHub (pinned to edf2fb608e)
Solutions
- Wrap each field value in an operator object, e.g. { title: { $contains: 'world' } } instead of a bare string or array.
- Validate the query shape (plain-object clauses only) before calling search.
- For multiple values, use one clause per element combined with $or (or $in where supported).
Example fix
// before
fuse.search({ title: ['world'] })
// after
fuse.search({ title: { $contains: 'world' } }) Defensive patterns
Strategy: validation
Validate before calling
const isOperatorObject = (v) =>
v !== null && typeof v === 'object' && !Array.isArray(v)
for (const [key, value] of Object.entries(query)) {
if (!isOperatorObject(value)) {
throw new TypeError(`Field '${key}' must be an operator object like { $eq: value }`)
}
}
fuse.search(query) Type guard
const isOperatorObject = (v) => v !== null && typeof v === 'object' && !Array.isArray(v)
Try / catch
try {
return fuse.search(query)
} catch (e) {
if (e.message.startsWith('Invalid field query')) {
console.warn('Malformed extended-search clause:', e.message)
return []
}
throw e
} Prevention
- Always wrap field values in $-operator objects in extended search.
- Validate query shape (plain objects, $-prefixed operators) before searching.
- Build queries with a helper that guarantees the operator-object schema.
When it happens
Trigger: An extended-search object query like { title: 'plain string' }, { title: ['a','b'] }, or { title: null } — any non-plain-object clause routed through the object-query compiler.
Common situations: Mixing plain-string query values with object syntax in extended search; queries built from JSON where values arrive as arrays; forgetting to wrap values in a $-operator object.
Related errors
- Extended search is not available
- Object query syntax is not available in this build
- Invalid value for key ${key}
AI-assisted analysis of krisk/Fuse@edf2fb608e (2026-09-02).
Data as JSON: /api/errors/a2dd70e63215a87d.
Report an issue: GitHub.