gatsbyjs/gatsby · error · Error

A plugin tried to update a node field that it doesn't own:

Error message

A plugin tried to update a node field that it doesn't own:

Node id: ${node.id}
Plugin: ${plugin.name}
name: ${name}
value: ${value}

What it means

createNodeField enforces single-owner semantics per field: the first plugin to set a given field name on a node is recorded in node.internal.fieldOwners[schemaFieldName], and any later createNodeField call for that same schema field from a different plugin throws. This prevents two plugins from silently clobbering each other's extension data on the same node. The schemaFieldName strips any ___NODE suffix so foreign-key fields share ownership with their scalar counterpart.

Source

Thrown at packages/gatsby/src/redux/actions/public.js:936

  actionOptions?: ActionOptions
) => {
  // Ensure required fields are set.
  if (!node.internal.fieldOwners) {
    node.internal.fieldOwners = {}
  }
  if (!node.fields) {
    node.fields = {}
  }

  // Normalized name of the field that will be used in schema
  const schemaFieldName = _.includes(name, `___NODE`)
    ? name.split(`___`)[0]
    : name

  // Check that this field isn't owned by another plugin.
  const fieldOwner = node.internal.fieldOwners[schemaFieldName]
  if (fieldOwner && fieldOwner !== plugin.name) {
    throw new Error(
      stripIndent`
      A plugin tried to update a node field that it doesn't own:

      Node id: ${node.id}
      Plugin: ${plugin.name}
      name: ${name}
      value: ${value}
      `
    )
  }

  // Update node
  node.fields[name] = value
  node.internal.fieldOwners[schemaFieldName] = plugin.name
  node = sanitizeNode(node)

  return {
    ...actionOptions,

View on GitHub (pinned to 8b06340921)

Solutions

  1. Rename the field your plugin writes so it does not collide (e.g. `myPluginSlug` instead of `slug`).
  2. If you legitimately own the field, ensure only one plugin calls createNodeField for that name; consolidate the logic.
  3. If you are replacing another plugin's behavior, disable/remove that plugin or use a different node type.
  4. Check the error's Plugin + name to see which two plugins conflict, then adjust ownership in config.

Example fix

// before - plugin 'gatsby-source-x' and 'gatsby-source-y' both do:
createNodeField({ node, name: `slug`, value: raw.slug })
// after - namespace per plugin
createNodeField({ node, name: `xSlug`, value: raw.slug })
Defensive patterns

Strategy: validation

Validate before calling

// Check ownership before calling createNodeField.
function safeCreateNodeField(actions, { node, name, value, pluginName }) {
  const schemaName = name.includes('___NODE') ? name.split('___')[0] : name
  const owner = node.internal.fieldOwners?.[schemaName]
  if (owner && owner !== pluginName) {
    // skip or rename instead of throwing
    actions.createNodeField({ node, name: `${pluginName}_${name}`, value })
    return
  }
  actions.createNodeField({ node, name, value })
}

Type guard

function canOwnField(node, name, pluginName) {
  const schemaName = name.includes('___NODE') ? name.split('___')[0] : name
  const owner = node?.internal?.fieldOwners?.[schemaName]
  return !owner || owner === pluginName
}

Prevention

When it happens

Trigger: Calling actions.createNodeField({ node, name, value }) from plugin B when node.internal.fieldOwners[name] (or [name.split('___')[0]]) was already set to plugin A.name, with A.name !== B.name. Fires inside the createNodeField action creator before the ADD_FIELD_TO_NODE action is dispatched.

Common situations: Two transformer/source plugins both writing the same field name (e.g. both set `slug` or `excerpt`) on shared node types; a custom plugin reusing a field name that gatsby-transformer-remark or another transformer already owns; copy-pasting field-extension code across plugins.

Related errors


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