{"record":{"id":"f100fbeac5ee7258","repo":"dgraph-io/dgraph","slug":"field-in-type-definition-cannot-have-tokenizers","errorCode":null,"errorMessage":"Field in type definition cannot have tokenizers","messagePattern":"Field in type definition cannot have tokenizers","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"worker/mutation.go","lineNumber":835,"sourceCode":"\n// typeSanityCheck performs basic sanity checks on the given type update.\nfunc typeSanityCheck(t *pb.TypeUpdate) error {\n\tfor _, field := range t.Fields {\n\t\tif x.ParseAttr(field.Predicate) == \"\" {\n\t\t\treturn errors.Errorf(\"Field in type definition must have a name\")\n\t\t}\n\n\t\tif field.ValueType == pb.Posting_OBJECT && field.ObjectTypeName == \"\" {\n\t\t\treturn errors.Errorf(\n\t\t\t\t\"Field with value type OBJECT must specify the name of the object type\")\n\t\t}\n\n\t\tif field.Directive != pb.SchemaUpdate_NONE {\n\t\t\treturn errors.Errorf(\"Field in type definition cannot have a directive\")\n\t\t}\n\n\t\tif len(field.Tokenizer) > 0 {\n\t\t\treturn errors.Errorf(\"Field in type definition cannot have tokenizers\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// CommitOverNetwork makes a proxy call to Zero to commit or abort a transaction.\nfunc CommitOverNetwork(ctx context.Context, tc *api.TxnContext) (uint64, error) {\n\tctx, span := otel.Tracer(\"\").Start(ctx, \"worker.CommitOverNetwork\")\n\tdefer span.End()\n\n\tclientDiscard := false\n\tif tc.Aborted {\n\t\t// The client called Discard\n\t\tostats.Record(ctx, x.TxnDiscards.M(1))\n\t\tclientDiscard = true\n\t}\n","sourceCodeStart":817,"sourceCodeEnd":853,"githubUrl":"https://github.com/dgraph-io/dgraph/blob/759e242be62c91f8d084da06ad0c8d21256d9c07/worker/mutation.go#L817-L853","documentation":"typeSanityCheck rejects type-definition fields that specify tokenizers. Tokenizers (hash, exact, term, fulltext, etc.) control indexing at the predicate level; a type definition only lists which predicates belong to the type, so attaching tokenizers there is invalid and the whole type update is refused.","triggerScenarios":"An alter/schema request where a field inside a `type` block has a non-empty Tokenizer array — usually because schema-building code copies pb.SchemaUpdate entries built for predicates (which carry tokenizers) into type definitions.","commonSituations":"Reusing one schema JSON/struct for both predicate and type definitions; migrating from predicate-centric tooling and forgetting tokenizers are not part of type blocks; hand-written DQL placing tokenizers inside type blocks.","solutions":["Strip tokenizers from the type block and declare them on the predicate line instead: `name: string @index(hash) .`","Ensure schema-generation code creates separate pb.SchemaUpdate entries for predicates (with Tokenizer) and types (with Tokenizer empty)","Re-send the alter request after separating predicate schema from type definitions"],"exampleFix":"// before\ntype Person {\n  name @index(hash)\n}\n// after\nname: string @index(hash) .\ntype Person {\n  name\n}","handlingStrategy":"validation","validationCode":"for _, f := range typeDef.Fields {\n    if len(f.Tokenizer) > 0 {\n        return fmt.Errorf(\"field %q: tokenizers must be declared on the predicate\", f.Predicate)\n    }\n}","typeGuard":"func fieldHasNoTokenizer(f *pb.SchemaUpdate) bool {\n    return len(f.Tokenizer) == 0\n}","tryCatchPattern":null,"preventionTips":["Declare tokenizers only with @index on predicate lines","Zero out Tokenizer when transforming predicate entries into type fields","Review generated schema for stray @index inside type blocks"],"tags":["dgraph","schema","type-definition","tokenizer"],"backgroundTag":"schema-validation-failed","analyzedSha":"759e242be62c91f8d084da06ad0c8d21256d9c07","analyzedAt":"2026-09-01T14:42:12.034Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}