{"record":{"id":"2d7137608c5e097c","repo":"dgraph-io/dgraph","slug":"id-written-to-group-id-file-must-be-a-positive-num","errorCode":null,"errorMessage":"ID written to group_id file must be a positive number","messagePattern":"ID written to group_id file must be a positive number","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"x/file.go","lineNumber":147,"sourceCode":"\t\t}\n\t}()\n\n\t_, err = file.Readdir(1)\n\tif err == nil {\n\t\treturn\n\t} else if err != io.EOF {\n\t\treturn\n\t}\n\n\terr = ErrMissingDir\n\treturn\n}\n\n// WriteGroupIdFile writes the given group ID to the group_id file inside the given\n// postings directory.\nfunc WriteGroupIdFile(pdir string, group_id uint32) error {\n\tif group_id == 0 {\n\t\treturn errors.Errorf(\"ID written to group_id file must be a positive number\")\n\t}\n\n\tgroupFile := filepath.Join(pdir, GroupIdFileName)\n\tf, err := os.OpenFile(groupFile, os.O_CREATE|os.O_WRONLY, 0600)\n\tif err != nil {\n\t\treturn nil\n\t}\n\tif _, err := f.WriteString(strconv.Itoa(int(group_id))); err != nil {\n\t\treturn err\n\t}\n\tif _, err := f.WriteString(\"\\n\"); err != nil {\n\t\treturn err\n\t}\n\treturn f.Close()\n}\n\n// ReadGroupIdFile reads the file at the given path and attempts to retrieve the\n// group ID stored in it.","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/dgraph-io/dgraph/blob/759e242be62c91f8d084da06ad0c8d21256d9c07/x/file.go#L129-L165","documentation":"WriteGroupIdFile persists a group ID into the group_id file inside a postings directory, and refuses to write a zero value because group IDs are 1-based; 0 signals an uninitialized/invalid group in Dgraph's Raft setup. The guard prevents creating a group_id file that would make a zero group look valid on subsequent reads.","triggerScenarios":"Calling WriteGroupIdFile(pdir, 0) directly, or indirectly via RunBulkLoader or RunOfflineRestore when the bulk loader / restore pipeline computed a zero group ID (e.g. unset or failed group assignment before writing server state).","commonSituations":"Automated pipelines that run the bulk loader programmatically before assigning a group; restore tooling invoked with an unset group parameter; custom tooling copying zero-valued config structs into the loader.","solutions":["Ensure the group ID passed to WriteGroupIdFile / RunBulkLoader / RunOfflineRestore is a nonzero value before the call","Fix upstream logic that computes the group ID so it cannot remain 0 (assign groups before running the loader/restore)","Reject group_id==0 at the pipeline entry point with a clearer configuration error"],"exampleFix":"// before\nerr := x.WriteGroupIdFile(pdir, cfg.GroupId) // panics with 'must be a positive number' when GroupId is 0\n// after\nif cfg.GroupId == 0 {\n    return fmt.Errorf(\"--group_id must be set (>=1); got %d\", cfg.GroupId)\n}\nerr := x.WriteGroupIdFile(pdir, cfg.GroupId)","handlingStrategy":"validation","validationCode":"if groupId == 0 {\n    return fmt.Errorf(\"group ID must be a positive number before calling WriteGroupIdFile (got %d)\", groupId)\n}\nif err := x.WriteGroupIdFile(pdir, groupId); err != nil {\n    return fmt.Errorf(\"writing group_id file: %w\", err)\n}","typeGuard":"func validGroupId(id uint32) bool { return id != 0 }","tryCatchPattern":null,"preventionTips":["Validate group IDs at CLI/config parsing time (reject 0 with a clear flag error)","Unit-test bulk loader/restore entry points with an unset group to fail fast upstream","Never write server state files manually; let the loader/restore path assign groups"],"tags":["group-id","bulk-loader","validation","dgraph"],"backgroundTag":"invalid-group-id","analyzedSha":"759e242be62c91f8d084da06ad0c8d21256d9c07","analyzedAt":"2026-09-01T14:42:12.034Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}