{"record":{"id":"c54b220812dfc429","repo":"dgraph-io/dgraph","slug":"index-for-predicate-v-is-missing-add-int-index","errorCode":null,"errorMessage":"index for predicate [%v] is missing, add int index with @unique","messagePattern":"index for predicate \\[(.+?)\\] is missing, add int index with @unique","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"worker/mutation.go","lineNumber":495,"sourceCode":"\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))\n\t\t} else {\n\t\t\treturn nil\n\t\t}\n\n\tcase pb.Posting_INT:\n\t\tif len(currentSchema.Tokenizer) == 0 {\n\t\t\treturn errors.Errorf(\"index for predicate [%v] is missing, add int index with @unique\",\n\t\t\t\tx.ParseAttr(currentSchema.Predicate))\n\t\t} else {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\treturn errors.Errorf(\"@unique directive not supported on [%v] type predicate\", currentSchema.ValueType.String())\n}\n\n// ValidateAndConvert checks compatibility or converts to the schema type if the storage type is\n// specified. If no storage type is specified then it converts to the schema type.\nfunc ValidateAndConvert(edge *pb.DirectedEdge, su *pb.SchemaUpdate) error {\n\n\tif isDeletePredicateEdge(edge) {\n\t\treturn nil\n\t}\n\tif types.TypeID(edge.ValueType) == types.DefaultID && isStarAll(edge.Value) {\n\t\treturn nil","sourceCodeStart":477,"sourceCodeEnd":513,"githubUrl":"https://github.com/dgraph-io/dgraph/blob/759e242be62c91f8d084da06ad0c8d21256d9c07/worker/mutation.go#L477-L513","documentation":"Int predicates marked @unique must be indexed with the 'int' tokenizer. When validateSchemaForUnique sees an int predicate with an empty tokenizer list, it rejects the schema because Dgraph cannot enforce uniqueness over an unindexed int predicate.","triggerScenarios":"Altering the schema to add @unique to an int predicate that has no @index(int) directive, e.g. `age int @unique .` with no tokenizer. Raised by checkSchema -> validateSchemaForUnique.","commonSituations":"Declaring a unique employee ID or external numeric key as `@unique` without remembering Dgraph (unlike some databases) requires the index to be spelled out; migrating schemas from SQL where unique implies its own index.","solutions":["Add the int index: `employeeId int @index(int) @unique .` and re-run the alter.","Remove @unique if uniqueness enforcement is not needed.","Verify with /state or the schema endpoint that the predicate now shows the int tokenizer."],"exampleFix":"// before (fails)\nemployeeId int @unique .\n\n// after\nemployeeId int @index(int) @unique .","handlingStrategy":"validation","validationCode":"# int predicates: @unique requires @index(int)\nfor pred in schemaChanges:\n    if pred.unique and pred.type == 'int' and 'int' not in (pred.index or []):\n        raise ValueError(f\"{pred.name}: add @index(int) with @unique\")","typeGuard":null,"tryCatchPattern":"// Go client\nif err := dg.Alter(ctx, op); err != nil {\n    if strings.Contains(err.Error(), \"add int index\") {\n        // rewrite schema: <pred> int @index(int) @unique . and retry\n    }\n}","preventionTips":["Treat @unique on int as shorthand that still demands @index(int).","Keep schema definitions in version control and lint for unique-without-index."],"tags":["dgraph","schema","unique-constraint","indexing"],"backgroundTag":"missing-unique-index","analyzedSha":"759e242be62c91f8d084da06ad0c8d21256d9c07","analyzedAt":"2026-09-01T14:42:12.034Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}