{"record":{"id":"a4dbfc32f96bc0f8","repo":"gatsbyjs/gatsby","slug":"array-is-an-invalid-filter-value-for-the-op-c","errorCode":null,"errorMessage":"Array is an invalid filter value for the `${op}` comparator","messagePattern":"Array is an invalid filter value for the `(.+?)` comparator","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/gatsby/src/datastore/in-memory/indexing.ts","lineNumber":820,"sourceCode":"      expensiveDedupeInline(arr)\n    }\n\n    return arr\n  }\n\n  if (filterValue == null) {\n    if (op === `$lt` || op === `$gt`) {\n      // Nothing is lt/gt null\n      return undefined\n    }\n\n    // This is an edge case and this value should be directly indexed\n    // For `lte`/`gte` this should only return nodes for `null`, not a \"range\"\n    return filterCache.byValue.get(filterValue)\n  }\n\n  if (Array.isArray(filterValue)) {\n    throw new Error(\n      \"Array is an invalid filter value for the `\" + op + \"` comparator\"\n    )\n  }\n\n  if (filterValue instanceof RegExp) {\n    // This is most likely an internal error, although it is possible for\n    // users to talk to this API more directly.\n    throw new Error(\n      `A RegExp instance is only valid for $regex and $glob comparators`\n    )\n  }\n\n  if (op === `$lt`) {\n    // First try a direct approach. If a value is queried that also exists then\n    // we can prevent a binary search through the whole list, O(1) vs O(log n)\n\n    const ranges = filterCache.meta.valueRangesAsc\n    const nodes = filterCache.meta.nodesByValueAsc","sourceCodeStart":802,"sourceCodeEnd":838,"githubUrl":"https://github.com/gatsbyjs/gatsby/blob/8b06340921ffdf23125a365b9c9923690cb62ce6/packages/gatsby/src/datastore/in-memory/indexing.ts#L802-L838","documentation":"When the in-memory evaluator reaches the scalar comparator branch (`$lt`, `$gt`, `$lte`, `$gte`, `$eq`, `$ne`, `$regex`/`$glob`), an Array value is meaningless and explicitly rejected. Arrays are only valid for `$in`/`$nin` (handled earlier). A `RegExp` instance here is also flagged as internal misuse.","triggerScenarios":"`filter: { age: { gte: [18] } }`, or piping an array into a scalar comparator; passing a pre-built `RegExp` to a non-regex comparator.","commonSituations":"Reusing a variable across `in` and range filters; programmatic filter builders that always wrap values in arrays.","solutions":["Pass a scalar to range/equality comparators.","Switch to `in`/`nin` if a set is genuinely intended.","Let Gatsby compile regex via the `regex`/`glob` string operators rather than passing `RegExp` instances."],"exampleFix":"// before\nfilter: { age: { gte: [18] } }\n// after\nfilter: { age: { gte: 18 } }","handlingStrategy":"validation","validationCode":"// Reject arrays for scalar comparators before sending the query.\nconst SCALAR_OPS = new Set([\"eq\", \"ne\", \"lt\", \"lte\", \"gt\", \"gte\", \"regex\", \"glob\"])\nfunction validateFilter(filter) {\n  for (const [field, ops] of Object.entries(filter)) {\n  for (const [op, value] of Object.entries(ops)) {\n  if (SCALAR_OPS.has(op) && Array.isArray(value)) {\n  throw new Error(`${field}.${op} must be a scalar, got array`)\n  }\n  }\n  }\n}\n","typeGuard":"function isScalarComparatorValue(v: unknown): boolean {\n  return v === null || (typeof v !== \"object\" && typeof v !== \"undefined\")\n}\n","tryCatchPattern":null,"preventionTips":["Keep a single filter-builder with per-operator type rules.","Never reuse the same variable across `in` and range filters."],"tags":["graphql","query","filter","datastore"],"backgroundTag":null,"analyzedSha":"8b06340921ffdf23125a365b9c9923690cb62ce6","analyzedAt":"2026-08-13T02:36:21.405Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}