gatsbyjs/gatsby · critical
Interfaces with the `nodeInterface` extension must have a fi
Error message
Interfaces with the `nodeInterface` extension must have a field `id` of type `ID!`. Check the type definition of `${typeComposer.getTypeName()}`. What it means
When a GraphQL interface type has the nodeInterface extension set, Gatsby requires it to declare a field named `id` of type `ID!` (non-null ID). This is the contract that allows the interface to participate in Gatsby's global node identification system. The panic fires when hasField('id') is false or the field type is not exactly ID!.
Source
Thrown at packages/gatsby/src/schema/schema.js:515
typeComposer,
extensions = {},
plugin,
createdFrom,
}) => {
typeComposer.setExtension(`createdFrom`, createdFrom)
typeComposer.setExtension(`plugin`, plugin ? plugin.name : null)
typeComposer.extendExtensions(extensions)
if (
typeComposer instanceof InterfaceTypeComposer &&
isNodeInterface(typeComposer)
) {
const hasCorrectIdField =
typeComposer.hasField(`id`) &&
typeComposer.getFieldType(`id`).toString() === `ID!`
if (!hasCorrectIdField) {
report.panic(
`Interfaces with the \`nodeInterface\` extension must have a field ` +
`\`id\` of type \`ID!\`. Check the type definition of ` +
`\`${typeComposer.getTypeName()}\`.`
)
}
}
if (
typeComposer instanceof ObjectTypeComposer ||
typeComposer instanceof InterfaceTypeComposer ||
typeComposer instanceof InputTypeComposer
) {
typeComposer.getFieldNames().forEach(fieldName => {
typeComposer.setFieldExtension(fieldName, `createdFrom`, createdFrom)
typeComposer.setFieldExtension(
fieldName,
`plugin`,
plugin ? plugin.name : nullView on GitHub (pinned to 8b06340921)
Solutions
- Add `id: ID!` to the interface type definition that has the @nodeInterface extension.
- If the field exists, ensure its type is exactly ID! not ID -- change nullable to non-null.
- If you did not intend this interface to be a node interface, remove the @nodeInterface extension / nodeInterface extension setting.
Example fix
// before
interface MyInterface @nodeInterface {
name: String
}
// after
interface MyInterface @nodeInterface {
id: ID!
name: String
} Defensive patterns
Strategy: validation
Validate before calling
// Validate node interface has id: ID!
function validateNodeInterface(typeDef) {
if (!/@nodeInterface/.test(typeDef)) return true
const hasIdField = /\bid\s*:\s*ID!/.test(typeDef)
return hasIdField
}
if (!validateNodeInterface(myTypeDef)) {
throw new Error('nodeInterface types must have id: ID!')
} Prevention
- Always include id: ID! when using the @nodeInterface extension.
- Double-check the field is non-null (ID!) not nullable (ID).
- Remove @nodeInterface if the interface is not meant to be a node.
When it happens
Trigger: Defining an interface type with the @nodeInterface extension (or programmatically setting the nodeInterface extension) that either omits the id field, makes it nullable (ID), or names the field something other than id.
Common situations: A plugin or gatsby-node.js uses createTypes with `interface NodeInterface @nodeInterface { ... }` but forgets the `id: ID!` field. Or the id field is declared as ID (nullable) instead of ID!.
Related errors
- Building schema failed
- Types implementing queryable interfaces must also implement
- stringifiedErrors
- Can't determine type for "${value}" in \`${selector}\`.
- Expected non-null field value.
AI-assisted analysis of gatsbyjs/gatsby@8b06340921 (2026-08-13).
Data as JSON: /api/errors/f7275d51cfcb2089.
Report an issue: GitHub.