dgraph-io/dgraph · error
could not drop index
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).
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
- Attribute: does not have proper index for comparison
- Attribute is not indexed.
- could not drop @upsert from
- Directive must be SchemaUpdate_INDEX when a tokenizer is…
- failed to enrich schema
AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01).
Data as JSON: /api/errors/c1b17fa681633c1d.
Report an issue: GitHub.
Appendix: 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)