dgraph-io/dgraph · error
could not drop index %v from [%v] predicate when @unique dir
Error message
could not drop index %v from [%v] predicate when @unique directive specified
What it means
Companion to the @upsert rule: a predicate already marked @unique must retain a valid index tokenizer across alterations, because uniqueness is enforced through the index. validateSchemaForUnique rejects updates where prevSchema.Unique is true but validTokenizer(currentSchema.Tokenizer) is false (tokenizer removed or replaced with nothing).
Source
Thrown at worker/mutation.go:475
}
func validateSchemaForUnique(prevSchema pb.SchemaUpdate, currentSchema *pb.SchemaUpdate) error {
validTokenizer := func(tokenizers []string) bool {
for _, value := range tokenizers {
if value == "hash" || value == "exact" || value == "int" {
return true
}
}
return false
}
if prevSchema.Predicate != "" {
if prevSchema.Upsert && !currentSchema.Upsert {
return errors.Errorf("could not drop @upsert from [%v] predicate when @unique directive specified",
x.ParseAttr(currentSchema.Predicate))
}
if prevSchema.Unique && !validTokenizer(currentSchema.Tokenizer) {
return errors.Errorf("could not drop index %v from [%v] predicate when @unique directive specified",
prevSchema.Tokenizer, x.ParseAttr(currentSchema.Predicate))
}
}
if !currentSchema.Upsert {
currentSchema.Upsert = true
}
switch currentSchema.ValueType {
case pb.Posting_STRING:
if len(currentSchema.Tokenizer) == 0 ||
(len(currentSchema.Tokenizer) > 0 && !validTokenizer(currentSchema.Tokenizer)) {
return errors.Errorf("index for predicate [%v] is missing, add either hash or exact index with @unique",
x.ParseAttr(currentSchema.Predicate))
} else {
return nil
}
case pb.Posting_INT:View on GitHub (pinned to 759e242be6)
Solutions
- Keep a valid tokenizer: e.g. 'email: string @index(hash) @upsert @unique'.
- If changing tokenizers, supply a replacement valid tokenizer in the same alteration rather than an empty list.
- Remove @unique (and @upsert) in the same update if the index is no longer wanted.
- Check the accepted tokenizer list (types and tokenizer names) for the predicate's value type before proposing the change.
Example fix
// before email: string @upsert @unique . // after email: string @index(hash) @upsert @unique .
Defensive patterns
Strategy: validation
Validate before calling
func validateUniqueTokenizer(prev, next *pb.SchemaUpdate) error {
if prev != nil && prev.Predicate != "" && prev.Unique && len(next.Tokenizer) == 0 {
return fmt.Errorf("predicate %s: @unique requires a valid index tokenizer", next.Predicate)
}
return nil
} Try / catch
err := dgraph.Alter(ctx, op)
if err != nil && strings.Contains(err.Error(), "could not drop index") {
// supply a valid tokenizer (or remove @unique) and retry
} Prevention
- Never regenerate @unique predicates without a tokenizer
- When changing tokenizers, always provide the new list in the same alteration
- Keep a schema test asserting unique preds retain tokenizers
When it happens
Trigger: Altering a '@unique' predicate by removing or invalidating its tokenizer, e.g. 'email: string @index(hash) @unique' changed to 'email: string @unique' or to an unsupported/empty tokenizer list.
Common situations: Switching tokenizers on a unique field without keeping a valid one; stripping @index during schema normalization; tooling that regenerates schemas and drops tokenizer arrays.
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
- Indexing not allowed on predicate %s of type %s
- Require type of tokenizer for pred: %s of type: %s for index
- Tokenizers present without indexing on attr %s
- failed to enrich schema
- Tokenizer must be specified while indexing a predicate: %+v
AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01).
Data as JSON: /api/errors/c1b17fa681633c1d.
Report an issue: GitHub.