payloadcms / payloadcms/payload
GraphQL schema creation fails with duplicate type name for recursive depth-limited block structures
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 44.8k
- Forks
- 4.2k
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 53
Description
Describe the Bug
Using the documented community pattern for recursive block structures — a depth-limited factory that returns one block config object per nesting level, all sharing the same slug and interfaceName (see e.g. discussion #4238) — breaks GraphQL schema creation entirely:
Error: Schema must contain uniquely named types but contains multiple types named "RecursiveItemBlock".
Every request against /api/graphql then returns a 500, including a trivial { __typename } query. TypeScript type generation handles the same pattern fine (deduplicates into interfaces), and the REST/Local APIs work normally — only the GraphQL schema build fails.
Root cause: the blocks handler in packages/graphql/src/schema/fieldToSchemaMap.ts deduplicates block types via the graphqlResult.types.blockTypes registry (keyed by block slug), but it only registers the newly built type after calling objectType.getFields(). That call eagerly resolves the type's fields, which walks nested blocks fields and re-enters the handler while the registry entry is still missing — so each nesting level constructs its own GraphQLObjectType with the same name, and new GraphQLSchema(...) rejects the schema.
Affects both v3 (reproduced on 3.85.1 and 3.86.0) and current main.
Fix PR (register the type before forcing field resolution, plus regression tests): #17300
Link to the code that reproduces this issue
https://github.com/alphanull/payload/tree/repro/graphql-recursive-blocks
(follows the reproduction guide: single commit adding a recursive block field to test/_community's Posts collection)
Reproduction Steps
- Check out the reproduction branch and run
pnpm install. - Run
pnpm dev:generate-graphql-schema _community(or startpnpm dev _communityand POST{"query":"{ __typename }"}to/api/graphql). - Schema creation throws
Schema must contain uniquely named types but contains multiple types named "RecursiveItemBlock".
The added config is just:
const buildRecursiveBlock = (depth: number): Block => {
const fields: Field[] = [{ name: 'label', type: 'text', required: true }]
if (depth > 1) {
fields.push({
name: 'children',
type: 'blocks',
blocks: [buildRecursiveBlock(depth - 1)],
})
}
return {
slug: 'recursiveItem',
fields,
interfaceName: 'RecursiveItemBlock',
}
}
// in a collection:
{
name: 'recursiveBlockField',
type: 'blocks',
blocks: [buildRecursiveBlock(3)],
}
Which area(s) are affected?
area: graphql
Environment Info
Binaries:
Node: 24.18.0
npm: 11.16.0
Yarn: N/A
pnpm: 11.5.2
Relevant Packages:
payload: 3.86.0
Operating System:
Platform: linux
Arch: arm64
Version: #1 SMP Thu Jun 25 13:45:40 UTC 2026
Available memory (MB): 7937
Available CPU cores: 4
Also reproduced against current main (4.0.0-beta.0) with Node 24.18.0.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in packages/graphql/src/schema/fieldToSchemaMap.ts and reproduce the failure with pnpm dev:generate-graphql-schema _community or the provided reproduction branch. Review the existing regression tests from PR #17300; done means recursive block configurations build a valid GraphQL schema without duplicate RecursiveItemBlock types.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- graphql, typescript
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 30/100