{"record":{"id":"f03dc6aa03c1429a","repo":"dgraph-io/dgraph","slug":"could-not-drop-upsert-from-v-predicate-when-u","errorCode":null,"errorMessage":"could not drop @upsert from [%v] predicate when @unique directive specified","messagePattern":"could not drop @upsert from \\[(.+?)\\] predicate when @unique directive specified","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"worker/mutation.go","lineNumber":470,"sourceCode":"\t\t\treturn errors.Errorf(\"Schema change not allowed from scalar to uid or vice versa\"+\n\t\t\t\t\" while there is data for pred: %s\", x.ParseAttr(s.Predicate))\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc validateSchemaForUnique(prevSchema pb.SchemaUpdate, currentSchema *pb.SchemaUpdate) error {\n\tvalidTokenizer := func(tokenizers []string) bool {\n\t\tfor _, value := range tokenizers {\n\t\t\tif value == \"hash\" || value == \"exact\" || value == \"int\" {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t\treturn false\n\t}\n\tif prevSchema.Predicate != \"\" {\n\t\tif prevSchema.Upsert && !currentSchema.Upsert {\n\t\t\treturn errors.Errorf(\"could not drop @upsert from [%v] predicate when @unique directive specified\",\n\t\t\t\tx.ParseAttr(currentSchema.Predicate))\n\t\t}\n\n\t\tif prevSchema.Unique && !validTokenizer(currentSchema.Tokenizer) {\n\t\t\treturn errors.Errorf(\"could not drop index %v from [%v] predicate when @unique directive specified\",\n\t\t\t\tprevSchema.Tokenizer, x.ParseAttr(currentSchema.Predicate))\n\t\t}\n\t}\n\tif !currentSchema.Upsert {\n\t\tcurrentSchema.Upsert = true\n\t}\n\tswitch currentSchema.ValueType {\n\tcase pb.Posting_STRING:\n\t\tif len(currentSchema.Tokenizer) == 0 ||\n\t\t\t(len(currentSchema.Tokenizer) > 0 && !validTokenizer(currentSchema.Tokenizer)) {\n\n\t\t\treturn errors.Errorf(\"index for predicate [%v] is missing, add either hash or exact index with @unique\",\n\t\t\t\tx.ParseAttr(currentSchema.Predicate))","sourceCodeStart":452,"sourceCodeEnd":488,"githubUrl":"https://github.com/dgraph-io/dgraph/blob/759e242be62c91f8d084da06ad0c8d21256d9c07/worker/mutation.go#L452-L488","documentation":"validateSchemaForUnique enforces invariants for @unique predicates: a predicate that is @unique must keep @upsert (uniqueness enforcement is implemented via upsert transactions) and must keep a valid index tokenizer. This error fires when an update tries to remove @upsert from a predicate whose previous schema had both Upsert and (implicitly) unique constraints.","triggerScenarios":"Altering a predicate that currently has '@upsert @unique' by dropping @upsert while keeping @unique, e.g. changing 'email: string @index(hash) @upsert @unique' to 'email: string @index(hash) @unique'.","commonSituations":"Schema cleanup removing directives one at a time without realizing @unique depends on @upsert; generated schemas where @upsert was stripped; misunderstandings that @unique alone suffices.","solutions":["Keep @upsert whenever @unique is present: 'email: string @index(hash) @upsert @unique'.","If upsert should be removed, remove @unique too in the same alteration.","Drop and recreate the predicate without the directives if the combination is no longer wanted (mind data retention).","Validate previous schema state (schema.State().Get) before proposing directive removals."],"exampleFix":"// before\nemail: string @index(hash) @unique .\n// after\nemail: string @index(hash) @upsert @unique .","handlingStrategy":"validation","validationCode":"func validateUniqueUpsert(prev, next *pb.SchemaUpdate) error {\n    if prev != nil && prev.Predicate != \"\" && prev.Unique && !next.Upsert {\n        return fmt.Errorf(\"predicate %s: @unique requires @upsert\", next.Predicate)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"err := dgraph.Alter(ctx, op)\nif err != nil && strings.Contains(err.Error(), \"could not drop @upsert\") {\n    // restore @upsert or remove @unique in the same update\n}","preventionTips":["Always emit @upsert and @unique as a pair","Remove both directives together if uniqueness is no longer needed","Diff against previous schema state before directive removals"],"tags":["dgraph","schema","unique","upsert"],"backgroundTag":"schema-validation-failed","analyzedSha":"759e242be62c91f8d084da06ad0c8d21256d9c07","analyzedAt":"2026-09-01T14:42:12.034Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}