dgraph-io/dgraph · error

could not insert duplicate value [%v] for predicate [%v]

Error message

could not insert duplicate value [%v] for predicate [%v]

What it means

Dgraph enforces @unique on a predicate during upsert mutations. When the mutation's value comes from a val(var) variable, verifyUnique iterates all existing UIDs holding the value and rejects the mutation if another node (different UID from the mutation subject) already stores the same value. This is the normal unique-constraint violation for value-variable mutations — Dgraph refuses to create a second node with the same value for a @unique predicate.

Source

Thrown at edgraph/server.go:1824

				return errors.Wrapf(err, "error while parsing [%v]", pred.Subject)
			}
		}

		var predValue interface{}
		if strings.HasPrefix(pred.ObjectId, "val(") {
			varName := qr.Vars[pred.ObjectId[4:len(pred.ObjectId)-1]]
			val, ok := varName.Vals.Get(0)
			if !ok {
				_, isValueGoingtoSet := varName.Vals.Get(subjectUid)
				if !isValueGoingtoSet {
					continue
				}

				results := qr.Vars[queryVar.valVar]
				err := results.Vals.Iterate(func(uidOfv uint64, v types.Val) error {
					varNameVal, _ := varName.Vals.Get(subjectUid)
					if v.Value == varNameVal.Value && uidOfv != subjectUid {
						return errors.Errorf("could not insert duplicate value [%v] for predicate [%v]",
							v.Value, pred.Predicate)
					}
					return nil
				})
				if err != nil {
					return err
				}
				continue
			} else {
				predValue = val.Value
			}
		} else {
			predValue = dql.TypeValFrom(pred.ObjectValue).Value
		}

		// Here, we check the uniqueness of the triple by comparing the result of the uniqueQuery with the triple.
		if !isEmpty(queryResult.Uids) {
			if len(queryResult.Uids.Uids) > 1 {

View on GitHub (pinned to 759e242be6)

Solutions

  1. Catch the error and treat it as a business-rule violation: run a query for the existing value and return that node instead of inserting
  2. Use an upsert block so the same value updates the existing node (blank node mapped to uid(var)) rather than inserting a duplicate
  3. Ensure the predicate has an index (e.g. @index(exact) for strings) — the unique check requires it and it makes dedup queries cheap
  4. If the duplicate is unintended legacy data, delete or merge the colliding nodes before re-running the mutation

Example fix

// before
upsert(query: "{ v as var(func: eq(email, \"a@b.com\")) }",
       mutation: "{ set { _:u <email> val(v) . } }")  // rejects if email exists elsewhere
// after
upsert(query: "{ v as var(func: eq(email, \"a@b.com\")) }",
       mutation: "{ set { uid(v) <email> \"a@b.com\" . uid(v) <name> \"A\" . } }")
Defensive patterns

Strategy: try-catch

Validate before calling

// Before insert, check existence:
q := `{ q(func: eq(email, $val)) { uid } }`
resp, _ := dg.NewTxn().Query(ctx, q)
// if resp has nodes, update instead of insert

Try / catch

_, err := txn.Mutate(ctx, mu)
if err != nil && strings.Contains(err.Error(), "could not insert duplicate value") {
	// fetch existing node by value and return/merge it
	return getExistingByValue(ctx, value)
}

Prevention

When it happens

Trigger: An upsert mutation sets predicate P (declared @unique in schema) with object val(v) where v holds a value, and the uniquecheck query finds an existing node with that same value whose UID differs from the subject UID (edgraph/server.go:1824).

Common situations: Creating a second user with the same email/username in a schema like `email: string @unique @index(exact)`; concurrent signups racing for the same email; re-running a seed script that inserts records already present; syncing data from an external system that already has rows with colliding values.

Related errors


AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01). Data as JSON: /api/errors/b3a6b003bda0ce48. Report an issue: GitHub.