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

  1. Alter the schema to add @lang: `name string @index(term) @lang .` then retry the mutation.
  2. Remove the language tag from the mutation value if a single untagged value is intended.
  3. 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

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


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