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

  1. Do not filter/sort on object/function fields; expose a scalar derived field instead.
  2. In the source plugin, normalise the field to a primitive (string/number/boolean) or an array of primitives before node creation.
  3. 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

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


AI-assisted analysis of gatsbyjs/gatsby@8b06340921 (2026-08-13). Data as JSON: /api/errors/4403b7584960616b. Report an issue: GitHub.