dgraph-io/dgraph · error
duplicate XID found: %s
Error message
duplicate XID found: %s
What it means
The same external ID (XID / @id field) value appears more than once within a single mutation request. Dgraph tracks XID occurrences while rewriting the mutation; a duplicate would create or reference the same logical node ambiguously, so it fails with this error. It notes the duplicated XID string.
Source
Thrown at graphql/resolve/mutation_rewriter.go:1893
// There are two cases:
// Case 1: We are at top level:
// We return an error if the same node is referenced twice at top level.
// Case 2: We are not at top level:
// We don't return an error if one of the occurrences of XID is a reference
// and other is definition.
// We return an error if both occurrences contain values other than XID and are
// not equal.
if xidMetadata.variableObjMap[variable] != nil {
// if we already encountered an object with same xid earlier, and this object is
// considered a duplicate of the existing object, then return error.
if xidMetadata.isDuplicateXid(atTopLevel, variable, obj, srcField) {
// TODO(Jatin): Add this error for inherited @id field with interface arg.
// Currently we don't return this error for the nested case when
// at both root and nested level we have same value of @id fields
// which have interface arg set and are inherited from same interface
// but are in different implementing type, we currently treat that as reference.
err := errors.Errorf("duplicate XID found: %s", xidString)
retErrors = append(retErrors, err)
return nil, nil, retErrors
}
// In the other case it is not duplicate, we update variableObjMap in case the new
// occurrence of XID is its description and the old occurrence was a reference.
// Example:
// obj = { "id": "1", "name": "name1"}
// xidMetadata.variableObjMap[variable] = { "id": "1" }
// In this case, as obj is the correct definition of the object, we update variableObjMap
oldObj := xidMetadata.variableObjMap[variable]
// TODO(Jatin): This condition also needs to change in accordance with multiple xids.
// Also consider the case when @id fields can be nullable.
if len(oldObj) == 1 && len(obj) > 1 {
// Continue execution to perform dfs in this case. There may be more nodes
// in the subtree of this node.
xidMetadata.variableObjMap[variable] = obj
} else {
// This is just a node reference. No need to proceed further.View on GitHub (pinned to 759e242be6)
Solutions
- Deduplicate the input: send the object with that XID only once and reference it elsewhere by ID/XID.
- Split the mutation into multiple requests, each containing a single occurrence of the XID.
- Fix payload generators so nested objects are emitted once and reused as references.
- Check for inherited @id fields from interfaces causing the same value to appear in different implementing types.
Example fix
// before
addAuthor(input: [{ username: "alice", name: "A" }, { username: "alice", name: "A2" }])
// after
addAuthor(input: [{ username: "alice", name: "A" }]) // one occurrence only Defensive patterns
Strategy: validation
Validate before calling
function assertNoDuplicateXids(objects, xidField) {
const seen = new Set();
for (const o of objects) {
const key = o && o[xidField];
if (key != null && key !== '') {
if (seen.has(key)) throw new Error(`duplicate XID found: ${key}`);
seen.add(key);
}
}
} Try / catch
try {
await client.mutate({ mutation: ADD_AUTHOR, variables: { input: authors } });
} catch (e) {
if (/duplicate XID found/.test(e.message)) {
const xid = e.message.match(/duplicate XID found: (.*)$/)[1];
// dedupe authors by xid and resend
} else throw e;
} Prevention
- Deduplicate bulk payloads by @id field before sending.
- Emit shared entities once and reference them by ID/XID in nested spots.
- Add unit tests on payload generators to assert XID uniqueness.
- Be careful with interface-inherited @id fields across implementing types.
When it happens
Trigger: A single add/update mutation whose input contains two or more objects sharing the same @id field value (e.g. two posts referencing author { username: "alice" } where alice's description appears twice), detected by isDuplicateXid during rewriting.
Common situations: Bulk-import payloads with repeated entities, list inputs generated from loops that re-emit the same parent object, or batch upserts combining set and nested references of the same XID.
Related errors
- Cycle detected: %s
- Missing fragment: %s
- PersistedQueryNotFound
- provided sha does not match query
- same sha returned %d queries
AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01).
Data as JSON: /api/errors/aae6848a3cc7418f.
Report an issue: GitHub.