gatsbyjs/gatsby · error · Error

createNodeId must be a function, was ${typeof createNodeId}

Error message

createNodeId must be a function, was ${typeof createNodeId}

What it means

createRemoteFileNode validates that `createNodeId` is a function before doing anything else. This guard exists because it is famously easy to pass the wrong createNodeId shape (see gatsbyjs/gatsby#6643). createNodeId turns a stable string into the Gatsby node id used to dedupe and reference the downloaded file. Anything that is not a function — undefined, a string, an object — fails fast with its runtime type.

Source

Thrown at packages/gatsby-source-filesystem/src/create-remote-file-node.js:115

 * @return {Promise<Object>}                  Returns the created node
 */
module.exports = function createRemoteFileNode({
  url,
  cache,
  createNode,
  getCache,
  parentNodeId = null,
  auth = {},
  httpHeaders = {},
  createNodeId,
  ext = null,
  name = null,
}) {
  // validation of the input
  // without this it's notoriously easy to pass in the wrong `createNodeId`
  // see gatsbyjs/gatsby#6643
  if (typeof createNodeId !== `function`) {
    throw new Error(
      `createNodeId must be a function, was ${typeof createNodeId}`
    )
  }
  if (typeof createNode !== `function`) {
    throw new Error(`createNode must be a function, was ${typeof createNode}`)
  }
  if (typeof getCache === `function`) {
    // use cache of this plugin and not cache of function caller
    cache = getCache(`gatsby-source-filesystem`)
  }
  if (typeof cache !== `object`) {
    throw new Error(
      `Neither "cache" or "getCache" was passed. getCache must be function that return Gatsby cache, "cache" must be the Gatsby cache, was ${typeof cache}`
    )
  }

  // Check if we already requested node for this remote file
  // and return stored promise if we did.

View on GitHub (pinned to 8b06340921)

Solutions

  1. Pass createNodeId from Gatsby helpers: in exports.sourceNodes = ({ actions, createNodeId, cache }) => { ... createRemoteFileNode({ url, createNodeId, createNode, cache }) }.
  2. Confirm createNodeId is the function reference, not a result of calling it (createNodeId vs createNodeId('foo')).
  3. If invoking outside sourceNodes, obtain createNodeId from the Gatsby node API helpers and forward it explicitly.
  4. Add a typeof createNodeId === 'function' assert at the entry of your own wrapper to fail with a clearer message.

Example fix

// before
await createRemoteFileNode({ url, cache, createNode })

// after
await createRemoteFileNode({
  url,
  cache,
  createNode,
  createNodeId,
})
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof createNodeId !== 'function') {
  throw new TypeError('createNodeId missing; forward it from Gatsby helpers')
}

Type guard

const isCreateNodeId = (v) => typeof v === 'function'

Try / catch

try { await createRemoteFileNode(opts) } catch (e) { if (/createNodeId must be a function/.test(e.message)) { reporter.panic('createNodeId not forwarded from helpers') } throw e }

Prevention

When it happens

Trigger: Calling createRemoteFileNode({ url }) without createNodeId; passing createNodeId: undefined; passing the createNodeId result string instead of the function; calling from a non-Gatsby context where helpers were not forwarded.

Common situations: Using createRemoteFileNode insidegatsby-node.js sourceNodes but destructuring helpers incorrectly; copy-pasting example that omits createNodeId; upgrading gatsby-source-filesystem where the parameter ordering/requirements tightened; calling from a standalone script with no Gatsby runtime.

Related errors


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