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

  1. Add a tokenizer to the predicate, e.g. 'name: string @index(hash)' or set s.Tokenizer = []string{"hash"} in the pb.SchemaUpdate.
  2. If indexing is not actually needed, drop the @index directive entirely (leave Directive unset / remove @index from the schema line).
  3. For vector predicates, supply a vector index spec (e.g. @index(hnsw(metric:"euclidean"))) so HasTokenizerOrVectorIndexSpec passes.
  4. 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

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


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)