{"record":{"id":"7e609b2fd54d014e","repo":"dgraph-io/dgraph","slug":"startts-must-be-provided","errorCode":null,"errorMessage":"StartTs must be provided","messagePattern":"StartTs must be provided","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"worker/draft.go","lineNumber":428,"sourceCode":"\t\t}\n\n\t\t// Propose initial types as well after a drop all as they would have been cleared.\n\t\tinitialTypes := schema.InitialTypes(x.RootNamespace)\n\t\tfor _, t := range initialTypes {\n\t\t\tif err := updateType(t.GetTypeName(), t, 1); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tif proposal.Mutations.DropOp == pb.Mutations_TYPE {\n\t\treturn schema.State().DeleteType(proposal.Mutations.DropValue, proposal.StartTs)\n\t}\n\n\tif proposal.Mutations.StartTs == 0 {\n\t\treturn errors.New(\"StartTs must be provided\")\n\t}\n\n\tif len(proposal.Mutations.Schema) > 0 || len(proposal.Mutations.Types) > 0 {\n\t\t// MaxAssigned would ensure that everything that's committed up until this point\n\t\t// would be picked up in building indexes. Any uncommitted txns would be cancelled\n\t\t// by detectPendingTxns below.\n\t\tstartTs := posting.Oracle().MaxAssigned()\n\n\t\tspan.AddEvent(\"Applying schema and types\")\n\t\tfor _, supdate := range proposal.Mutations.Schema {\n\t\t\t// We should not need to check for predicate move here.\n\t\t\tif err := detectPendingTxns(supdate.Predicate); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif err := runSchemaMutation(ctx, proposal.Mutations.Schema, startTs); err != nil {\n\t\t\treturn err","sourceCodeStart":410,"sourceCodeEnd":446,"githubUrl":"https://github.com/dgraph-io/dgraph/blob/759e242be62c91f8d084da06ad0c8d21256d9c07/worker/draft.go#L410-L446","documentation":"Raised in applyMutations (worker/draft.go:428) when a committed mutation proposal arrives with StartTs == 0. Every mutation must carry the transaction's start timestamp for watermark/index tracking; zero means the proposal was malformed.","triggerScenarios":"A peer or client submits a Mutations proposal to Raft with StartTs unset (0) — usually from buggy or version-mismatched alpha code, not from end-user API calls.","commonSituations":"Mixed cluster versions where an older alpha sends proposals the newer server considers incomplete; custom tooling writing directly to the internal Raft proposal API; corrupted task queue entries.","solutions":["Ensure all Dgraph alpha/zero nodes run the same version; upgrade or downgrade to a consistent release.","Regenerate/fix the proposal producer so StartTs is populated from txn.RunAtTs.","If a single bad proposal is wedging the group, restart the affected alpha; the proposal will be skipped or retried cleanly."],"exampleFix":"// before\nproposal := &pb.Mutations{Schema: sch}\n// after: always set StartTs\nproposal := &pb.Mutations{Schema: sch, StartTs: startTs}","handlingStrategy":"validation","validationCode":"if proposal.Mutations == nil || proposal.Mutations.StartTs == 0 { return errors.New(\"proposal missing StartTs\") }","typeGuard":"func validMutationProposal(m *pb.Mutations) bool {\n    return m != nil && m.StartTs != 0\n}","tryCatchPattern":null,"preventionTips":["Run identical Dgraph versions across the cluster.","Never hand-craft internal Raft proposals; use the official client APIs.","Validate proposals at the producer before pushing to Raft."],"tags":["dgraph","raft","mutations","internal"],"backgroundTag":"missing-required-argument","analyzedSha":"759e242be62c91f8d084da06ad0c8d21256d9c07","analyzedAt":"2026-09-01T14:42:12.034Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}