dgraph-io/dgraph · error
Tokenizer must be specified while indexing a predicate: %+v
Error message
Tokenizer must be specified while indexing a predicate: %+v
What it means
checkSchema in worker/mutation.go validates schema mutations before proposing them to the cluster. When a schema update carries Directive == SchemaUpdate_INDEX (i.e. the predicate is being (re)indexed), at least one tokenizer (or a vector index spec) must also be supplied. Dgraph refuses an index directive with no tokenizer because it cannot build an index without knowing how to tokenize values.
Solutions
- Add a tokenizer to the predicate, e.g. 'name: string @index(hash)' or set s.Tokenizer = []string{"hash"} in the pb.SchemaUpdate.
- If indexing is not actually needed, drop the @index directive entirely (leave Directive unset / remove @index from the schema line).
- For vector predicates, supply a vector index spec (e.g. @index(hnsw(metric:"euclidean"))) so HasTokenizerOrVectorIndexSpec passes.
- Validate the schema locally with schema.Parse or a dry run before proposing the mutation.
Example fix
// before name: string @index . // after name: string @index(hash) .
Defensive patterns
Strategy: validation
Validate before calling
func validateIndexDirective(s *pb.SchemaUpdate) error {
if s.Directive == pb.SchemaUpdate_INDEX && !schema.HasTokenizerOrVectorIndexSpec(s) {
return fmt.Errorf("predicate %s: @index requires a tokenizer", s.Predicate)
}
return nil
} Type guard
func hasTokenizer(s *pb.SchemaUpdate) bool {
return len(s.Tokenizer) > 0
} Try / catch
err := dgraph.Alter(ctx, op)
if err != nil && strings.Contains(err.Error(), "Tokenizer must be specified") {
// fix schema: add tokenizer or drop @index, then retry
} Prevention
- Always pair @index with a tokenizer in parentheses
- Lint DQL schema files for @index without tokenizer
- Unit-test generated schemas against checkSchema
When it happens
Trigger: Sending a schema (via ALTER / client.Alter / runSchemaMutation / createSchema) with '@index' on a predicate but no tokenizer arguments, e.g. 'name: string @index .' without the tokenizer, or building a pb.SchemaUpdate with Directive: pb.SchemaUpdate_INDEX and an empty Tokenizer slice and no vector index spec.
Common situations: Hand-written DQL schema blocks where '@index' is written without parentheses/tokenizer; programmatic schema generation that sets Directive but forgets to append Tokenizers; copying a schema and stripping tokenizers while keeping @index; upgrading from a schema that had a default tokenizer assumption.
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
- Directive must be SchemaUpdate_INDEX when a tokenizer is…
- failed to enrich schema
- Require type of tokenizer for pred
- Tokenizers present without indexing on attr
- Attribute: does not have proper index for comparison
AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01).
Data as JSON: /api/errors/e96dacdeee0a769c.
Report an issue: GitHub.
Appendix: source
Thrown at worker/mutation.go:394
}
return false
}
func checkSchema(s *pb.SchemaUpdate) error {
if s == nil {
return errors.Errorf("Nil schema")
}
if x.ParseAttr(s.Predicate) == "" {
return errors.Errorf("No predicate specified in schema mutation")
}
if x.IsInternalPredicate(s.Predicate) {
return errors.Errorf("Cannot create user-defined predicate with internal name %s",
x.ParseAttr(s.Predicate))
}
if s.Directive == pb.SchemaUpdate_INDEX && !schema.HasTokenizerOrVectorIndexSpec(s) {
return errors.Errorf("Tokenizer must be specified while indexing a predicate: %+v", s)
}
if schema.HasTokenizerOrVectorIndexSpec(s) && s.Directive != pb.SchemaUpdate_INDEX {
return errors.Errorf("Directive must be SchemaUpdate_INDEX when a tokenizer is specified")
}
typ := types.TypeID(s.ValueType)
if typ == types.UidID && s.Directive == pb.SchemaUpdate_INDEX {
// index on uid type
return errors.Errorf("Index not allowed on predicate of type uid on predicate %s",
x.ParseAttr(s.Predicate))
} else if typ != types.UidID && s.Directive == pb.SchemaUpdate_REVERSE {
// reverse on non-uid type
return errors.Errorf("Cannot reverse for non-uid type on predicate %s",
x.ParseAttr(s.Predicate))
}
// If schema update has upsert directive, it should have index directive.View on GitHub (pinned to 759e242be6)