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 Discard

View on GitHub (pinned to 759e242be6)

Solutions

  1. Remove all directives from the type block; keep them only on the corresponding predicate declarations in the schema section
  2. e.g. write `type Person { name address }` and declare `name: string @index(exact) .` separately at the predicate level
  3. 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

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


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