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]
What
With
@uniqueon a@langpredicate, the same value under two different language tags is rejectedwhen both edges are in one mutation and accepted when they are in separate mutations.
Verified on v25.3.8.
Repro
Schema:
Both in one mutation:
gives
could not insert duplicate value [same] for predicate [gxid].The same two values in separate mutations are both accepted, landing on two nodes:
Cause
The two uniqueness checks disagree about whether language is part of a value's identity.
addQueryIfUniquescopes the DB-level query per language:verifyUniqueWithinMutationcompares predicate, value, and subject, and never looks atLang:So the in-request check treats
"x"@enand"x"@fras one value while the DB check treats them astwo.
Which side should change
Probably the in-request check.
@langvalues are stored per language independently, sogxid@enand
gxid@frare distinct values and uniqueness should be scoped per language, which is whataddQueryIfUniquealready does. That makes the fix addingLangto the comparison inverifyUniqueWithinMutation.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 anupsert fails validation for an unrelated reason: