{"record":{"id":"0dd2a2aea1196118","repo":"dgraph-io/dgraph","slug":"id-s-isn-t-a-s","errorCode":null,"errorMessage":"ID \"%s\" isn't a %s","messagePattern":"ID \"(.+?)\" isn't a (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"graphql/resolve/mutation_rewriter.go","lineNumber":1393,"sourceCode":"\t\t\t\t// We return an error if this is at toplevel. Else, we return the ID reference\n\t\t\t\tif atTopLevel {\n\t\t\t\t\t// We need to conceal the error because we might be leaking information to the user if it\n\t\t\t\t\t// tries to add duplicate data to the field with @id.\n\t\t\t\t\tvar err error\n\t\t\t\t\tif queryAuthSelector(typ) == nil {\n\t\t\t\t\t\terr = x.GqlErrorf(\"id %s already exists for type %s\", idVal.(string), typ.Name())\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// This error will only be reported in debug mode.\n\t\t\t\t\t\terr = x.GqlErrorf(\"GraphQL debug: id already exists for type %s\", typ.Name())\n\t\t\t\t\t}\n\t\t\t\t\tretErrors = append(retErrors, err)\n\t\t\t\t\treturn nil, upsertVar, retErrors\n\t\t\t\t} else {\n\t\t\t\t\treturn asIDReference(ctx, idVal, srcField, srcUID, varGen, mutationType == UpdateWithRemove), upsertVar, nil\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Reference UID does not exist. This is an error.\n\t\t\t\terr := errors.Errorf(\"ID \\\"%s\\\" isn't a %s\", idVal.(string), srcField.Type().Name())\n\t\t\t\tretErrors = append(retErrors, err)\n\t\t\t\treturn nil, upsertVar, retErrors\n\t\t\t}\n\t\t}\n\t}\n\n\txids := typ.XIDFields()\n\tif len(xids) != 0 {\n\t\t// multipleNodesForSameID is true when there are multiple nodes present\n\t\t// in a result of existence queries\n\t\tmultipleNodesForSameID := gotMultipleExistingNodes(xids, obj, typ, varGen, idExistence)\n\t\t// xidVariables stores the variable names for each XID.\n\t\tvar xidVariables []string\n\t\tfor _, xid := range xids {\n\t\t\tvar xidString string\n\t\t\tif xidVal, ok := obj[xid.Name()]; ok && xidVal != nil {\n\t\t\t\txidString, _ = extractVal(xidVal, xid.Name(), xid.Type().Name())\n\t\t\t\tvariable = varGen.Next(typ, xid.Name(), xidString, false)","sourceCodeStart":1375,"sourceCodeEnd":1411,"githubUrl":"https://github.com/dgraph-io/dgraph/blob/759e242be62c91f8d084da06ad0c8d21256d9c07/graphql/resolve/mutation_rewriter.go#L1375-L1411","documentation":"During GraphQL mutation rewriting, a node referenced by its UID (ID field) was checked against the results of existence queries and no node with that UID exists in the database. Since referenced nodes must already exist, Dgraph rejects the mutation rather than silently creating a dangling reference. The error names the offending ID value and the expected type name.","triggerScenarios":"Calling an add/update mutation (e.g. addPost with set/add or update with a nested reference) where a nested object supplies an `id` field whose UID does not exist in Dgraph, and the mutation is not at top level (so it cannot be treated as an upsert/create).","commonSituations":"Hardcoded or copied UIDs from another environment (dev vs prod), deleted nodes still referenced by client code, stale test fixtures, or typos/truncation in a UID string.","solutions":["Query the node by that UID first to confirm it exists; create it (or use an upsert mutation with @id/XID) before referencing it.","Use the node's external ID (XID) instead of the raw UID so Dgraph can run an existence query and reference or upsert correctly.","Fix stale references in fixtures/seed data by regenerating UIDs from the target environment.","Check the mutation structure: an ID reference at the top level of an Update mutation is allowed, but nested references must point to existing nodes."],"exampleFix":"// before\naddPost(input: { title: \"hi\", author: { id: \"0x1234\" } }) // 0x1234 does not exist\n// after\naddPost(input: { title: \"hi\", author: { username: \"alice\" } }) // reference via @id field, or create the author first","handlingStrategy":"validation","validationCode":"async function uidExists(dgraph, uid, typeName) {\n  const q = `query { n(func: uid(${uid})) @filter(type(${typeName})) { uid } }`;\n  const res = await dgraph.newTxn().query(q);\n  return res.data.n.length > 0;\n}\n// before the mutation: if (!(await uidExists(client, input.author.id, \"Author\"))) throw new Error(\"referenced Author does not exist\");","typeGuard":"function isValidUid(v) {\n  return typeof v === 'string' && /^0x[0-9a-fA-F]+$/.test(v);\n}","tryCatchPattern":"try {\n  await client.mutate({ mutation: ADD_POST, variables: { input } });\n} catch (e) {\n  if (/ID \\\".*\\\" isn't a/.test(e.message)) {\n    // create the referenced node or switch to an @id/XID reference\n  } else throw e;\n}","preventionTips":["Query existence of UIDs before referencing them in nested mutations.","Prefer @id/XID references over raw UIDs in application code.","Never copy UIDs between environments; regenerate fixtures per environment.","Use upsert blocks when you want create-or-reference semantics."],"tags":["graphql","mutation","dangling-reference"],"backgroundTag":"referenced-entity-not-found","analyzedSha":"759e242be62c91f8d084da06ad0c8d21256d9c07","analyzedAt":"2026-09-01T14:42:12.034Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}