Skip to content

fix(unique): @unique and @lang disagree on whether language is part of value identity #9815

Description

@matthewmcneely

What

With @unique on a @lang predicate, the same value under two different language tags is rejected
when both edges are in one mutation and accepted when they are in separate mutations.

Verified on v25.3.8.

Repro

Schema:

gxid: string @unique @index(exact) @lang .

Both in one mutation:

{ set {
  _:a <gxid> "same"@en .
  _:b <gxid> "same"@fr .
} }

gives could not insert duplicate value [same] for predicate [gxid].

The same two values in separate mutations are both accepted, landing on two nodes:

{ set { _:a <gxid> "sep"@en . } }
{ set { _:b <gxid> "sep"@fr . } }

{ q(func: eq(gxid@en,"sep")) { uid gxid@en } }  =>  [{"uid":"0xb","gxid@en":"sep"}]
{ q(func: eq(gxid@fr,"sep")) { uid gxid@fr } }  =>  [{"uid":"0xc","gxid@fr":"sep"}]

Cause

The two uniqueness checks disagree about whether language is part of a value's identity.

addQueryIfUnique scopes the DB-level query per language:

predicateName = fmt.Sprintf("%v@%v", predicateName, pred.Lang)

verifyUniqueWithinMutation compares predicate, value, and subject, and never looks at Lang:

if pred2.Predicate == pred1.Predicate && dql.TypeValFrom(pred2.ObjectValue).Value == pred1Value &&
    pred2.Subject != pred1.Subject {

So the in-request check treats "x"@en and "x"@fr as one value while the DB check treats them as
two.

Which side should change

Probably the in-request check. @lang values are stored per language independently, so gxid@en
and gxid@fr are distinct values and uniqueness should be scoped per language, which is what
addQueryIfUnique already does. That makes the fix adding Lang to the comparison in
verifyUniqueWithinMutation.

Either resolution is defensible, but the two paths should agree.

Minor, related

The generated __dgraph_uniquecheck_<n>__ variable names leak into user-facing DQL errors when an
upsert fails validation for an unrelated reason:

Some variables are defined but not used
Defined:[__dgraph_uniquecheck_0__ __dgraph_uniquecheck_4294967296__ v]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions