{"record":{"id":"fc8754667532be1b","repo":"gatsbyjs/gatsby","slug":"the-plugin-ownername-created-a-node-of-a-type","errorCode":null,"errorMessage":"The plugin \"${ownerName}\" created a node of a type owned by another plugin.\n\nThe node type \"${typeName}\" is owned by \"${existingTypeOwnerNameByTypeName}\".\n\nIf you copy and pasted code from elsewhere, you'll need to pick a new type name\nfor your new node(s).\n\n${fullNode ? stripIndent(`The node object passed to \"createNode\":\n\n              ${JSON.stringify(fullNode, null, 4)}\\n`) : ``}\nThe plugin creating the node:\n\n${JSON.stringify(plugin, null, 4)}","messagePattern":"The plugin \"(.+?)\" created a node of a type owned by another plugin\\.\n\nThe node type \"(.+?)\" is owned by \"(.+?)\"\\.\n\nIf you copy and pasted code from elsewhere, you'll need to pick a new type name\nfor your new node\\(s\\)\\.\n\n(.+?)\\\\n`\\) : ``\\}\nThe plugin creating the node:\n\n(.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/gatsby/src/redux/reducers/type-owners.ts","lineNumber":37,"sourceCode":"    reportOnce(`No plugin owner for type \"${typeName}\"`)\n    return typeOwners\n  }\n\n  const existingOwnerTypes = typeOwners.pluginsToTypes.get(ownerName)\n\n  if (!existingOwnerTypes) {\n    typeOwners.pluginsToTypes.set(ownerName, new Set([typeName]))\n  } else {\n    existingOwnerTypes.add(typeName)\n  }\n\n  const existingTypeOwnerNameByTypeName =\n    typeOwners.typesToPlugins.get(typeName)\n\n  if (!existingTypeOwnerNameByTypeName) {\n    typeOwners.typesToPlugins.set(typeName, ownerName)\n  } else if (existingTypeOwnerNameByTypeName !== ownerName) {\n    throw new Error(stripIndent`\n      The plugin \"${ownerName}\" created a node of a type owned by another plugin.\n\n      The node type \"${typeName}\" is owned by \"${existingTypeOwnerNameByTypeName}\".\n\n      If you copy and pasted code from elsewhere, you'll need to pick a new type name\n      for your new node(s).\n\n      ${\n        fullNode\n          ? stripIndent(\n              `The node object passed to \"createNode\":\n\n              ${JSON.stringify(fullNode, null, 4)}\\n`\n            )\n          : ``\n      }\n      The plugin creating the node:\n","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/gatsbyjs/gatsby/blob/8b06340921ffdf23125a365b9c9923690cb62ce6/packages/gatsby/src/redux/reducers/type-owners.ts#L19-L55","documentation":"Gatsby enforces that each node internal.type is owned by exactly one plugin. setTypeOwner records the first plugin to create a given type in typeOwners.typesToPlugins and throws if a different plugin later tries to createNode a node of that same type. This prevents two source plugins from emitting overlapping GraphQL types, which would corrupt the schema. The error names both plugins, the contested type, and (if available) dumps the offending node and plugin objects.","triggerScenarios":"Plugin B calls createNode with a node whose node.internal.type equals a type name already recorded for plugin A (A !== B). The check runs on every CREATE_NODE in the type-owners reducer.","commonSituations":"Copy-pasting a source plugin to make a variant but keeping the same node.internal.type (e.g. 'MarkdownRemark' or 'SourceX'); installing two source plugins that both claim a generic type like 'File' or a CMS type; a forked plugin reusing the original's type names.","solutions":["Pick a unique type name for your plugin (e.g. prefix it: 'MySourcePost' instead of 'Post').","If you forked a plugin, rename all internal.type values it emits.","Uninstall/disable the duplicate source plugin so only one owns the type.","If you are composing plugins, have one delegate node creation to the owner rather than both creating."],"exampleFix":"// before - forked plugin reuses type\ncreateNode({ id, internal: { type: `MarkdownRemark`, ... } })\n// after\ncreateNode({ id, internal: { type: `MyBlogMarkdownRemark`, ... } })","handlingStrategy":"validation","validationCode":"// Verify type ownership before createNode to fail with a clearer message.\nconst usedTypes = new Map() // typeName -> pluginName\nfunction claimType(typeName, pluginName) {\n  const prev = usedTypes.get(typeName)\n  if (prev && prev !== pluginName) {\n    throw new Error(`Type '${typeName}' already owned by '${prev}'`)\n  }\n  usedTypes.set(typeName, pluginName)\n}","typeGuard":"function isUniqueNodeType(typeName, pluginName, registry) {\n  const prev = registry.get(typeName)\n  return !prev || prev === pluginName\n}","tryCatchPattern":null,"preventionTips":["Prefix node types with your plugin name to guarantee global uniqueness.","When forking a plugin, rename all internal.type values.","Document the types your plugin owns to avoid collisions."],"tags":["type-owners","createnode","ownership","schema","plugin-api"],"backgroundTag":null,"analyzedSha":"8b06340921ffdf23125a365b9c9923690cb62ce6","analyzedAt":"2026-08-13T02:36:21.405Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}