dgraph-io/dgraph · error
Attr: [%v] should have @lang directive in schema to mutate e
Error message
Attr: [%v] should have @lang directive in schema to mutate edge: [%v]
What it means
If a mutation edge carries a language tag (@lang value on the edge) but the predicate's schema was not declared with the @lang directive, ValidateAndConvert rejects the mutation: Dgraph will not store language-tagged values for a predicate not marked @lang.
Source
Thrown at worker/mutation.go:526
if isDeletePredicateEdge(edge) {
return nil
}
if types.TypeID(edge.ValueType) == types.DefaultID && isStarAll(edge.Value) {
return nil
}
if strings.Contains(su.Predicate, hnsw.VecKeyword) {
return errors.Errorf("Not allowed to insert mutations in vector index keys, edge: [%v]", edge)
}
storageType := posting.TypeID(edge)
schemaType := types.TypeID(su.ValueType)
// type checks
switch {
case edge.Lang != "" && !su.GetLang():
return errors.Errorf("Attr: [%v] should have @lang directive in schema to mutate edge: [%v]",
x.ParseAttr(edge.Attr), edge)
case !schemaType.IsScalar() && !storageType.IsScalar():
return nil
case !schemaType.IsScalar() && storageType.IsScalar():
return errors.Errorf("Input for predicate %q of type uid is scalar. Edge: %v",
x.ParseAttr(edge.Attr), edge)
case schemaType.IsScalar() && !storageType.IsScalar():
return errors.Errorf("Input for predicate %q of type scalar is uid. Edge: %v",
x.ParseAttr(edge.Attr), edge)
case schemaType == types.TypeID(pb.Posting_VFLOAT):
if !(storageType == types.TypeID(pb.Posting_VFLOAT) || storageType == types.TypeID(pb.Posting_STRING) ||
storageType == types.TypeID(pb.Posting_DEFAULT)) {
return errors.Errorf("Input for predicate %q of type vector is not vector."+
" Did you forget to add quotes before []?. Edge: %v", x.ParseAttr(edge.Attr), edge)View on GitHub (pinned to 759e242be6)
Solutions
- Alter the schema to add @lang: `name string @index(term) @lang .` then retry the mutation.
- Remove the language tag from the mutation value if a single untagged value is intended.
- Check the current schema (query schema(pred: ["name"])) to confirm whether @lang is set.
Example fix
// schema before (fails) name string @index(term) . // mutation <0x1> <name> "Hello"@en . // schema after name string @index(term) @lang .
Defensive patterns
Strategy: validation
Validate before calling
async function assertLangDirective(dgraph, pred) {
const schema = await dgraph.newTxn().query(`schema(pred: ["${pred}"])`)
const p = schema.data.schema[0]
if (!p.lang) throw new Error(`${pred} lacks @lang; cannot write language-tagged values`)
} Try / catch
try {
await txn.mutate(mu)
} catch (e) {
if (String(e).includes('should have @lang directive')) {
// alter schema to add @lang, then retry the mutation
}
} Prevention
- Add @lang to any predicate you plan to localize before shipping i18n mutations.
- Keep schema in sync across dev/staging/prod environments.
- Strip language tags for single-language fields instead of relying on @lang everywhere.
When it happens
Trigger: Sending a mutation with a language-tagged edge (e.g. RDF with @en, or edge.Lang set in the DirectedEdge) for a predicate whose SchemaUpdate lacks the Lang flag, i.e. schema is `name string @index(term) .` without @lang.
Common situations: Localizing an app by adding @en/@fr/@de values before updating the schema; GraphQL or client drivers that set language tags automatically; schema altered in one environment but not another.
Related errors
- failure to convert edge type: '%+v' to schema type: '%+v'
- illegal rune found "%c", expecting {
- JSON map is followed by illegal rune "%c"
- Malformed JSON
- error creating indexer for %s: %w
AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01).
Data as JSON: /api/errors/aa55aea70b6cc5d2.
Report an issue: GitHub.