gatsbyjs/gatsby · error · Error
Bad value at ${path}: ${inspect(fieldValue)}
Error message
Bad value at ${path}: ${inspect(fieldValue)} What it means
LMDB indexes serialise each indexed field via `jsValueToLmdbKey`. If a field value cannot be converted to a valid key (returns `undefined` — e.g. a function, symbol, or unrecognised object), index insertion aborts with the node type, dotted field path, and node id. This protects index integrity rather than writing a corrupt key.
Source
Thrown at packages/gatsby/src/datastore/lmdb/query/create-index.ts:192
function prepareIndexKeys(
node: IGatsbyNode,
resolvedFields: { [field: string]: unknown } | undefined,
indexName: string,
indexFields: IndexFields
): { keys: Array<IndexKey>; multiKeyFields: Array<string> } {
// TODO: use index id vs index name (shorter)
const indexKeyElements: Array<Array<IndexFieldValue>> = []
const multiKeyFields: Array<string> = []
indexKeyElements.push([indexName])
for (const dottedField of indexFields.keys()) {
const fieldValue = resolveFieldValue(dottedField, node, resolvedFields)
let indexFieldValue = jsValueToLmdbKey(fieldValue)
// Got value that can't be stored in lmdb key
if (typeof indexFieldValue === `undefined`) {
const path = `${node.internal.type}.${dottedField} (id: ${node.id})`
throw new Error(`Bad value at ${path}: ${inspect(fieldValue)}`)
}
indexFieldValue = Array.isArray(indexFieldValue)
? indexFieldValue.flat() // FIXME
: [indexFieldValue]
indexKeyElements.push(indexFieldValue)
if (indexFieldValue.length > 1) {
multiKeyFields.push(dottedField)
}
}
indexKeyElements.push([node.internal.counter])
return { keys: cartesianProduct(...indexKeyElements), multiKeyFields }
}
async function lockIndex(
context: IIndexingContext,View on GitHub (pinned to 8b06340921)
Solutions
- Do not filter/sort on object/function fields; expose a scalar derived field instead.
- In the source plugin, normalise the field to a primitive (string/number/boolean) or an array of primitives before node creation.
- If the field is metadata-only, keep it out of `___gatsby` queryable surface.
Example fix
// before: node.field = { toString() {...}, rank: () => 1 } // indexed & filtered
// after: node.fieldKey = "computed-scalar"; node.rank = 1 // index these instead Defensive patterns
Strategy: validation
Validate before calling
// Source-plugin side: ensure indexed fields are primitives or arrays of primitives.
function assertIndexable(fieldValue, fieldPath) {
const ok = fieldValue === null ||
["string", "number", "boolean"].includes(typeof fieldValue) ||
Array.isArray(fieldValue)
if (!ok) throw new Error(`Field ${fieldPath} is not indexable: ${typeof fieldValue}`)
}
Type guard
type Indexable = string | number | boolean | null | Indexable[]
function isIndexable(v: unknown): v is Indexable {
if (v === null || ["string", "number", "boolean"].includes(typeof v)) return true
if (Array.isArray(v)) return v.every(isIndexable)
return false
}
Prevention
- Do not expose functions/class instances/symbols on queryable fields.
- Derive scalar index fields from rich objects in `onCreateNode`.
When it happens
Trigger: A node has a field used in a filter/index whose value is a non-serialisable type (function, class instance, symbol, complex object not reduced to primitives).
Common situations: Source plugins returning rich objects/functions on fields that are then queried with a filter (which triggers indexing); custom resolvers attaching non-primitive metadata.
Related errors
- The argument to the `in` predicate should be an array
- ${filter.comparator} value must not be an array
- Range filter ${predicate} should not have array value
- Range filter ${predicate} should not have value of type ${ty
- Bad filter value for predicate ${filter.comparator}: ${inspe
AI-assisted analysis of gatsbyjs/gatsby@8b06340921 (2026-08-13).
Data as JSON: /api/errors/4403b7584960616b.
Report an issue: GitHub.