dgraph-io/dgraph · error
Field in type definition cannot have a directive
Error message
Field in type definition cannot have a directive
What it means
typeSanityCheck rejects any type-definition field that carries a directive (e.g. @index, @upsert, @reverse, @lang). Directives belong to predicate (schema) definitions, not to type definitions, so a type block that re-declares a field with a directive set on pb.SchemaUpdate fails this check. This keeps the type system purely about grouping predicates under a named type.
Source
Thrown at worker/mutation.go:831
}
return nil
}
// typeSanityCheck performs basic sanity checks on the given type update.
func typeSanityCheck(t *pb.TypeUpdate) error {
for _, field := range t.Fields {
if x.ParseAttr(field.Predicate) == "" {
return errors.Errorf("Field in type definition must have a name")
}
if field.ValueType == pb.Posting_OBJECT && field.ObjectTypeName == "" {
return errors.Errorf(
"Field with value type OBJECT must specify the name of the object type")
}
if field.Directive != pb.SchemaUpdate_NONE {
return errors.Errorf("Field in type definition cannot have a directive")
}
if len(field.Tokenizer) > 0 {
return errors.Errorf("Field in type definition cannot have tokenizers")
}
}
return nil
}
// CommitOverNetwork makes a proxy call to Zero to commit or abort a transaction.
func CommitOverNetwork(ctx context.Context, tc *api.TxnContext) (uint64, error) {
ctx, span := otel.Tracer("").Start(ctx, "worker.CommitOverNetwork")
defer span.End()
clientDiscard := false
if tc.Aborted {
// The client called DiscardView on GitHub (pinned to 759e242be6)
Solutions
- Remove all directives from the type block; keep them only on the corresponding predicate declarations in the schema section
- e.g. write `type Person { name address }` and declare `name: string @index(exact) .` separately at the predicate level
- Fix any code generator that populates field.Directive when building pb.SchemaUpdate type definitions
Example fix
// before
type Person {
name @index(exact)
}
// after
name: string @index(exact) .
type Person {
name
} Defensive patterns
Strategy: validation
Validate before calling
for _, f := range typeDef.Fields {
if f.Directive != pb.SchemaUpdate_NONE {
return fmt.Errorf("field %q: directives belong on predicates, not type defs", f.Predicate)
}
} Type guard
func fieldHasNoDirective(f *pb.SchemaUpdate) bool {
return f.Directive == pb.SchemaUpdate_NONE
} Prevention
- Keep directives (@index, @upsert, @reverse) only in predicate schema lines
- Use separate structs/entries for predicate schema and type definitions
- Copy-paste check: never reuse predicate pb.SchemaUpdate objects as type fields
When it happens
Trigger: Sending an alter/schema update whose `type` block fields have Directive set to anything other than pb.SchemaUpdate_NONE — typically when a generator copies predicate schema entries (with their directives) into type definitions.
Common situations: Schema migration scripts that reuse the same struct for predicates and type fields, accidentally carrying @index/@upsert directives into type blocks; hand-written DQL where directives are placed inside a `type X { }` block instead of at the predicate line.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Field with value type OBJECT must specify the name of the ob
- Field in type definition cannot have tokenizers
- illegal rune found "%c", expecting {
- JSON map is followed by illegal rune "%c"
- Malformed JSON
AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01).
Data as JSON: /api/errors/1222435c490f599a.
Report an issue: GitHub.