{"record":{"id":"0d10430dabe72dcf","repo":"gatsbyjs/gatsby","slug":"range-filter-predicate-should-not-have-value-of","errorCode":null,"errorMessage":"Range filter ${predicate} should not have value of type ${typeof value}","messagePattern":"Range filter (.+?) should not have value of type (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/gatsby/src/datastore/lmdb/query/filter-using-index.ts","lineNumber":650,"sourceCode":"  predicate: DbComparator,\n  edge: ValueEdges = ValueEdges.EQ\n): IndexFieldValue | RangeEdgeBefore | RangeEdgeAfter | undefined {\n  const fieldQueries = getFieldQueries(context.dbQueries, indexField)\n  for (const dbQuery of fieldQueries) {\n    if (context.usedQueries.has(dbQuery)) {\n      continue\n    }\n    const filterStatement = getFilterStatement(dbQuery)\n    if (filterStatement.comparator !== predicate) {\n      continue\n    }\n    context.usedQueries.add(dbQuery)\n    const value = filterStatement.value\n    if (Array.isArray(value)) {\n      throw new Error(`Range filter ${predicate} should not have array value`)\n    }\n    if (typeof value === `object` && value !== null) {\n      throw new Error(\n        `Range filter ${predicate} should not have value of type ${typeof value}`\n      )\n    }\n    if (edge === 0) {\n      return value\n    }\n    return edge < 0 ? getValueEdgeBefore(value) : getValueEdgeAfter(value)\n  }\n  return undefined\n}\n\n/**\n * Returns the edge after the given value, suitable for lmdb range queries.\n *\n * Example:\n * Get all items from index starting with [\"foo\"] prefix up to the next existing prefix:\n *\n * ```js","sourceCodeStart":632,"sourceCodeEnd":668,"githubUrl":"https://github.com/gatsbyjs/gatsby/blob/8b06340921ffdf23125a365b9c9923690cb62ce6/packages/gatsby/src/datastore/lmdb/query/filter-using-index.ts#L632-L668","documentation":"Same `resolveRangeEdge` path: a range predicate's value is a non-null object (not a primitive). LMDB keys cannot represent arbitrary objects, so the planner rejects it with the value's `typeof`.","triggerScenarios":"`filter: { age: { gt: { value: 10 } } }` (object instead of scalar) on an indexed range field.","commonSituations":"Nested filter objects accidentally passed through; double-wrapped filter builders.","solutions":["Flatten the filter value to a scalar for range predicates.","Inspect the filter object structure to ensure each comparator maps to a primitive."],"exampleFix":"// before\nfilter: { age: { gt: { value: 10 } } }\n// after\nfilter: { age: { gt: 10 } }","handlingStrategy":"validation","validationCode":"function validateRangeFilters(filter) {\n  for (const ops of Object.values(filter)) {\n  for (const [op, value] of Object.entries(ops)) {\n  if ([\"lt\", \"lte\", \"gt\", \"gte\"].includes(op) && typeof value === \"object\" && value !== null && !Array.isArray(value)) {\n  throw new Error(`Range ${op} must be primitive, got object`)\n  }\n  }\n  }\n}\n","typeGuard":"function isPrimitiveRangeValue(v: unknown): v is string | number | boolean | null {\n  return v === null || [\"string\", \"number\", \"boolean\"].includes(typeof v)\n}\n","tryCatchPattern":null,"preventionTips":["Flatten filter objects; never nest an object under a range comparator.","Validate filters against a schema before sending the query."],"tags":["graphql","query","filter","lmdb","indexing","datastore"],"backgroundTag":null,"analyzedSha":"8b06340921ffdf23125a365b9c9923690cb62ce6","analyzedAt":"2026-08-13T02:36:21.405Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}