{"record":{"id":"f7f339e6e9ca1816","repo":"juicedata/juicefs","slug":"expect-group-s-but-got-s","errorCode":null,"errorMessage":"expect group %s but got %s","messagePattern":"expect group (.+?) but got (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"cmd/objbench.go","lineNumber":1108,"sourceCode":"\t\t}\n\t\treturn utils.ErrNotSUP\n\t})\n\n\tfunFSCase(\"change owner/group\", func() error {\n\t\tif (strings.HasPrefix(blob.String(), \"file://\") || strings.HasPrefix(blob.String(), \"jfs://\")) && os.Getuid() != 0 {\n\t\t\treturn errors.New(\"root required\")\n\t\t}\n\t\tif err := fi.Chown(key, \"nobody\", groupName); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to chown object %s\", err)\n\t\t}\n\t\tif objInfo, err := blob.Head(ctx, key); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to head object %s\", err)\n\t\t} else if info, ok := objInfo.(object.File); ok {\n\t\t\tif info.Owner() != \"nobody\" {\n\t\t\t\treturn fmt.Errorf(\"expect owner nobody but got %s\", info.Owner())\n\t\t\t}\n\t\t\tif info.Group() != groupName {\n\t\t\t\treturn fmt.Errorf(\"expect group %s but got %s\", groupName, info.Group())\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t})\n\n\tfunFSCase(\"change permission\", func() error {\n\t\tif err := fi.Chmod(key, 0777); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif objInfo, err := blob.Head(ctx, key); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to head object %s\", err)\n\t\t} else if info, ok := objInfo.(object.File); ok {\n\t\t\tif info.Mode()&0xFFF != 0777 {\n\t\t\t\treturn fmt.Errorf(\"expect mode %o but got %o\", 0777, info.Mode())\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t})","sourceCodeStart":1090,"sourceCodeEnd":1126,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/cmd/objbench.go#L1090-L1126","documentation":"Verification failure in the same case: after Chown(key, \"nobody\", groupName), Head reports the object's Group does not equal groupName. The group part of the ownership change was not persisted or the metadata served is stale. Only checked when Head returns object.File metadata.","triggerScenarios":"fi.Chown succeeded but info.Group() != groupName on the follow-up Head: backend ignored the group change, groupName doesn't exist on the storage side, or stale metadata was returned.","commonSituations":"Groups not synced between the client host and the storage backend, FUSE/file backends where group changes need root, cached Head responses, backends mapping group names to IDs inconsistently.","solutions":["Confirm groupName exists on the storage side (getent group) and matches exactly (case-sensitive).","Run as root so the group change is actually applied.","Invalidate caches / re-Head after a short delay to rule out staleness.","Skip the case for backends lacking group metadata support."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"if _, err := user.LookupGroup(groupName); err != nil {\n\treturn fmt.Errorf(\"group %s not resolvable: %w\", groupName, err)\n}\nif objInfo, err := blob.Head(ctx, key); err == nil {\n\tif _, ok := objInfo.(object.File); !ok {\n\t\treturn utils.ErrNotSUP\n\t}\n}","typeGuard":"func asFile(o object.ObjectMetadata) (object.File, bool) {\n\tf, ok := o.(object.File)\n\treturn f, ok\n}","tryCatchPattern":null,"preventionTips":["Ensure the group name exists and matches exactly on the storage side","Run with root privileges so group changes apply","Re-Head after cache invalidation to avoid stale group info","Skip group verification for backends without group metadata"],"tags":["permissions","group","verification"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}