{"record":{"id":"4088527d77e1a941","repo":"gatsbyjs/gatsby","slug":"plugins-creating-nodes-can-not-set-data-on-the-res","errorCode":null,"errorMessage":"Plugins creating nodes can not set data on the reserved field \"fields\"\nas this is reserved for plugins which wish to extend your nodes.\n\nIf your plugin didn't add \"fields\" you're probably seeing this\nerror because you're reusing an old node object.\n\nNode:\n\n${JSON.stringify(node, null, 4)}\n\nPlugin that created the node:\n\n${JSON.stringify(plugin, null, 4)}","messagePattern":"Plugins creating nodes can not set data on the reserved field \"fields\"\nas this is reserved for plugins which wish to extend your nodes\\.\n\nIf your plugin didn't add \"fields\" you're probably seeing this\nerror because you're reusing an old node object\\.\n\nNode:\n\n(.+?)\n\nPlugin that created the node:\n\n(.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/gatsby/src/redux/actions/public.js","lineNumber":754,"sourceCode":"        errorObj.filePath = possiblyCodeFrame.fileName\n        errorObj.location = {\n          start: {\n            line: possiblyCodeFrame.line,\n            column: possiblyCodeFrame.column,\n          },\n        }\n      }\n\n      report.error(errorObj)\n      hasErroredBecauseOfNodeValidation.add(result.error.message)\n    }\n\n    return { type: `VALIDATION_ERROR`, error: true }\n  }\n\n  // Ensure node isn't directly setting fields.\n  if (node.fields) {\n    throw new Error(\n      stripIndent`\n      Plugins creating nodes can not set data on the reserved field \"fields\"\n      as this is reserved for plugins which wish to extend your nodes.\n\n      If your plugin didn't add \"fields\" you're probably seeing this\n      error because you're reusing an old node object.\n\n      Node:\n\n      ${JSON.stringify(node, null, 4)}\n\n      Plugin that created the node:\n\n      ${JSON.stringify(plugin, null, 4)}\n    `\n    )\n  }\n","sourceCodeStart":736,"sourceCodeEnd":772,"githubUrl":"https://github.com/gatsbyjs/gatsby/blob/8b06340921ffdf23125a365b9c9923690cb62ce6/packages/gatsby/src/redux/actions/public.js#L736-L772","documentation":"Gatsby reserves the node.fields object for extensions added via the createNodeField action; source plugins must not populate it directly when calling createNode. The reducer/action layer checks `if (node.fields)` on the incoming node and throws, because allowing a plugin to seed fields would bypass ownership tracking (node.internal.fieldOwners) that lets multiple plugins extend the same node without colliding. The message also flags the common cause: reusing a stale node object that already had fields attached.","triggerScenarios":"Calling actions.createNode({ ..., fields: { ... } }) with a node object whose top-level `fields` property is truthy. Typically happens when an object retrieved via getNode() (which already has fields from a prior createNodeField call) is mutated and passed back into createNode.","commonSituations":"Copying/pasting source-plugin code and forgetting to strip fields; fetching an existing node, augmenting it, and re-creating it; transforming a node and passing the whole original (with its fields) into createNode for the derived type.","solutions":["Remove the `fields` key from the object passed to createNode: `const { fields, ...nodeToCreate } = node`.","Use createNodeField({ node, name, value }) after createNode to attach derived/extension data.","Build the node from scratch (only internal + top-level data fields) rather than reusing a node that already went through the pipeline.","If you only need to update extension data on an existing node, do not call createNode again - use createNodeField."],"exampleFix":"// before\nconst existing = getNode(id)\ncreateNode({ ...existing, myNewData: 123 }) // existing.fields leaks in\n// after\nconst { fields, ...base } = existing\ncreateNode({ ...base, myNewData: 123 })\ncreateNodeField({ node: getNode(id), name: `myNewData`, value: 123 })","handlingStrategy":"validation","validationCode":"// Strip reserved keys before createNode.\nfunction sanitizeNodeForCreate(node) {\n  const { fields, ...rest } = node\n  return rest\n}\n// usage: createNode(sanitizeNodeForCreate(raw))","typeGuard":"function isCreateSafeNode(node) {\n  return node && typeof node === 'object' && !('fields' in node) &&\n    node.internal && typeof node.internal.type === 'string'\n}","tryCatchPattern":null,"preventionTips":["Never spread an existing node (from getNode) into createNode without stripping fields.","Build nodes from primitives/internal only; add extension data via createNodeField.","Add a unit test asserting createNode payloads have no fields key."],"tags":["nodes","createnode","fields","plugin-api"],"backgroundTag":null,"analyzedSha":"8b06340921ffdf23125a365b9c9923690cb62ce6","analyzedAt":"2026-08-13T02:36:21.405Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}