dgraph-io/dgraph · critical
Found multiple nodes with ID: %s
Error message
Found multiple nodes with ID: %s
What it means
During a mutation, an upsert/query block produced more than one UID for a single query name (qNameToUID counted >1 results). Since the node should be uniquely identified by its XID or UID, multiple matches indicate data corruption — duplicate nodes sharing the same external ID — so the mutation is aborted rather than silently modifying the wrong node.
Source
Thrown at graphql/resolve/mutation.go:356
// "Project_1" : "0x123",
// "Column_2" : "0x234"
// }
// As only Add and Update mutations generate queries using RewriteQueries,
// qNameToUID map will be non-empty only in case of Add or Update Mutation.
qNameToUID := make(map[string]string)
for key, result := range queryResultMap {
count := 0
typ := qNameToType[key]
for _, res := range result {
if x.HasString(res.Types, typ) {
qNameToUID[key] = res.Uid
count++
}
}
if count > 1 {
// Found multiple UIDs for query. This should ideally not happen.
// This indicates that there are multiple nodes with same XIDs / UIDs. Throw an error.
err = errors.New(fmt.Sprintf("Found multiple nodes with ID: %s", qNameToUID[key]))
gqlErr := schema.GQLWrapLocationf(
err, mutation.Location(), "mutation %s failed", mutation.Name())
return emptyResult(gqlErr), resolverFailed
}
}
// Create upserts, delete mutations, update mutations, add mutations.
upserts, err = mr.mutationRewriter.Rewrite(ctx, mutation, qNameToUID)
if err != nil {
return emptyResult(schema.GQLWrapf(err, "couldn't rewrite mutation %s", mutation.Name())),
resolverFailed
}
if len(upserts) == 0 {
return &Resolved{
Data: completeMutationResult(mutation, nil, 0),
Field: mutation,
Err: nil,View on GitHub (pinned to 759e242be6)
Solutions
- Find and delete/merge the duplicate nodes sharing the same XID in the underlying Dgraph data
- Run a data cleanup query listing all nodes for the offending XID to identify duplicates
- Enforce XID uniqueness by re-adding the @id directive and cleaning legacy data
- Re-run the mutation after de-duplication
Example fix
// before
upsert(query: q(filter: { xid: { eq: "dup-1" } })) // matches 2 nodes
// after
cleanup duplicates so xid "dup-1" maps to exactly one node, then retry Defensive patterns
Strategy: validation
Validate before calling
// before updating, verify uniqueness
const dupes = await dqlQuery(`query q(filter: { xid: { eq: "${xid}" } }) { count }`);
if (dupes.data.q.length > 1) throw new Error(`Found multiple nodes with ID: ${xid}`); Try / catch
try {
await updateMutation(input);
} catch (err) {
if (err.message.startsWith('Found multiple nodes with ID:')) {
// run dedup cleanup for the reported ID before retrying
}
} Prevention
- Always use @id directive with unique external IDs
- Clean legacy imports for XID duplicates before enabling updates
- Avoid manual DQL writes that bypass uniqueness
- Monitor for duplicate-XID metrics/alerts
When it happens
Trigger: An update/delete mutation whose @id/XID filter matches more than one stored node; concurrent writes created two nodes with the same external identifier; the uniqueness check (count > 1) fires in rewriteAndExecute.
Common situations: Data imported before the @id/XID uniqueness enforcement was added; manual DQL writes bypassing GraphQL validation; a race in concurrent Add mutations inserting the same XID twice.
Related errors
- UID must to be greater than 0
- UID not found/generated for xid %s
- Subject and object both should be *. Got: %+v
- Subject should be > 0 for nquad: %+v
- ObjectId should be > 0 for nquad: %+v
AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01).
Data as JSON: /api/errors/ee07296c8c19fa9f.
Report an issue: GitHub.