gatsbyjs/gatsby · error · Error

Nodes can only be updated by their owner. Node "${node.id}"

Error message

Nodes can only be updated by their owner. Node "${node.id}" is owned by "${oldNode.internal.owner}" and another plugin "${owner}" tried to update it.

What it means

When createNode is called for an id that already exists (oldNode present), the type-owners reducer checks that the new node's internal.owner matches the existing node's internal.owner. If they differ it throws, because a node id is an identity contract and allowing a second plugin to 'recreate' (overwrite) a node owned by another plugin would silently hijack data. This complements per-type ownership with per-node ownership continuity.

Source

Thrown at packages/gatsby/src/redux/reducers/type-owners.ts:115

            The plugin deleting the node:

            ${JSON.stringify(plugin, null, 4)}
        `)
        }
      }

      return typeOwners
    }
    case `CREATE_NODE`: {
      const { plugin, oldNode, payload: node } = action
      const { owner, type } = node.internal

      setTypeOwner(type, plugin, typeOwners, node)

      // If the node has been created in the past, check that
      // the current plugin is the same as the previous.
      if (oldNode && oldNode.internal.owner !== owner) {
        throw new Error(
          stripIndent`
            Nodes can only be updated by their owner. Node "${node.id}" is
            owned by "${oldNode.internal.owner}" and another plugin "${owner}"
            tried to update it.
          `
        )
      }

      return typeOwners
    }

    default:
      return typeOwners
  }
}

View on GitHub (pinned to 8b06340921)

Solutions

  1. Namespace your node ids so they cannot collide with other plugins (e.g. `source-x:${rawId}`).
  2. Clear .cache after changing which plugin owns a type so stale oldNode entries are gone.
  3. Ensure the same plugin consistently creates the same node id across builds.

Example fix

// before
createNode({ id: raw.slug, internal: { type: `Post`, ... } }) // collides across plugins
// after
createNode({ id: `my-source-${raw.slug}`, internal: { type: `Post`, ... } })
Defensive patterns

Strategy: validation

Validate before calling

// Namespace node ids so they cannot collide across plugins.
function namespacedId(pluginName, rawId) {
  return `${pluginName}::${rawId}`
}
// createNode({ id: namespacedId('my-source', raw.id), ... })

Type guard

function isStableNamespacedId(id, pluginName) {
  return typeof id === 'string' && id.startsWith(`${pluginName}::`)
}

Prevention

When it happens

Trigger: Plugin B calls createNode with an id that already exists in state and was created by plugin A (oldNode.internal.owner !== B's owner). Reached when two plugins generate colliding ids, or the same id is reused by different plugins across rebuilds.

Common situations: ID collision: two plugins generating the same id prefix/scheme (e.g. both using `path-1`); switching the plugin that owns a node type without clearing cache; a plugin change that altered internal.owner derivation while old nodes still persist.

Related errors


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