gatsbyjs/gatsby · critical

The `namespace` parameter passed to createNodeId must be a S

Error message

The `namespace` parameter passed to createNodeId must be a String (got ${typeof namespace})

What it means

createNodeId takes a namespace (typically the Gatsby createNodeId bound by createNodeFactory or passed as the second argument) used to scope UUID generation. The namespace must be a string. If it is undefined, null, or any non-string type, Gatsby panics. This check only runs when id is a string (the else-if chain).

Source

Thrown at packages/gatsby/src/utils/create-node-id.ts:44

 * to make sure the id ends up being short, whatever the input size was.
 *
 * Note: UUID is relatively slow because it calls into the native crypto library to generate SHA-1 hashes.
 *       We do need the low collision rate of SHA-1 so we use a local (global) cache to speed up repetitive calls
 *
 * @param {String | Number} id - A string of arbitrary length
 * @param {String} namespace - Namespace to use for UUID
 *
 * @return {String} - UUID
 */
export function createNodeId(id: string | number, namespace: string): string {
  if (typeof id === `number`) {
    id = id.toString()
  } else if (typeof id !== `string`) {
    report.panic(
      `The \`id\` parameter passed to createNodeId must be a String or Number (got ${typeof id})`
    )
  } else if (typeof namespace !== `string`) {
    report.panic(
      `The \`namespace\` parameter passed to createNodeId must be a String (got ${typeof namespace})`
    )
  }

  let nsHash = unprefixedCache.get(namespace)
  if (!nsHash) {
    nsHash = uuidv5(namespace, seedConstant) as string
    unprefixedCache.set(namespace, nsHash)
  }

  // Calling uuid is relatively expensive because it calls into crypto for sha1.
  // We use a local map to cache calls with the same ns+id pair, which helps a lot.
  let nsCache = namespacedCache.get(namespace)
  if (!nsCache) {
    nsCache = new Map()
    namespacedCache.set(namespace, nsCache)
  }

View on GitHub (pinned to 8b06340921)

Solutions

  1. Use actions.createNodeId(id) from sourceNodes/onCreateNode context -- Gatsby pre-binds the correct namespace.
  2. If calling the raw utility, pass a valid string namespace: createNodeId(id, 'my-plugin-namespace').
  3. Verify the namespace variable is defined before calling -- add a guard or default.

Example fix

// before -- raw import loses namespace
const { createNodeId } = require('gatsby/utils')
const id = createNodeId('post-1') // namespace is undefined

// after -- use actions-bound version
exports.sourceNodes = ({ actions, createNodeId }) => {
  const id = createNodeId('post-1') // namespace pre-bound
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate namespace before calling createNodeId
function validateCreateNodeIdNamespace(namespace) {
  if (typeof namespace !== 'string') {
    throw new Error('createNodeId namespace must be string, got ' + typeof namespace)
  }
}

Type guard

function isValidNamespace(ns) {
  return typeof ns === 'string' && ns.length > 0
}

Prevention

When it happens

Trigger: Calling createNodeId('some-id') without the second argument, or passing a non-string namespace. This happens when the bound createNodeId function from actions or gatsby-node context is not used, or when calling the raw createNodeId from gatsby/utils without a namespace.

Common situations: Importing createNodeId directly from gatsby/node-utils instead of using the one provided in actions.createNodeId (which has the namespace pre-bound). A source plugin that destructures incorrectly and loses the namespace binding. Passing undefined as namespace due to a variable not being set.

Related errors


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