{"record":{"id":"33d6b20b621a4942","repo":"juicedata/juicefs","slug":"first-key-should-be-empty-string-but-got-s","errorCode":null,"errorMessage":"first key should be empty string, but got %s","messagePattern":"first key should be empty string, but got (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/objbench.go","lineNumber":896,"sourceCode":"\t\t\treturn fmt.Errorf(\"deleting a non-existent object returns an error %v\", err)\n\t\t}\n\t\treturn nil\n\t})\n\n\trunCase(\"list objects\", func(blob object.ObjectStorage) error {\n\t\tbr := []byte(\"hello\")\n\t\tif err := blob.Put(ctx, key, bytes.NewReader(br)); err != nil {\n\t\t\treturn fmt.Errorf(\"put object failed: %s\", err)\n\t\t}\n\t\tdefer blob.Delete(ctx, key) //nolint:errcheck\n\t\tif isFileSystem {\n\t\t\tobjs, err := listAll(ctx, blob, \"\", \"\", 2)\n\t\t\tif err == nil {\n\t\t\t\tif len(objs) != 2 {\n\t\t\t\t\treturn fmt.Errorf(\"list should return 2 keys, but got %d\", len(objs))\n\t\t\t\t}\n\t\t\t\tif objs[0].Key() != \"\" {\n\t\t\t\t\treturn fmt.Errorf(\"first key should be empty string, but got %s\", objs[0].Key())\n\t\t\t\t}\n\t\t\t\tif objs[0].Size() != 0 {\n\t\t\t\t\treturn fmt.Errorf(\"first object size should be 0, but got %d\", objs[0].Size())\n\t\t\t\t}\n\t\t\t\tif objs[1].Key() != key {\n\t\t\t\t\treturn fmt.Errorf(\"first key should be test, but got %s\", objs[1].Key())\n\t\t\t\t}\n\t\t\t\tif objs[1].Size() != 5 {\n\t\t\t\t\treturn fmt.Errorf(\"size of first key shold be 5, but got %v\", objs[1].Size())\n\t\t\t\t}\n\t\t\t\tnow := time.Now()\n\t\t\t\tif objs[1].Mtime().Before(now.Add(-30*time.Second)) || objs[1].Mtime().After(now.Add(time.Second*30)) {\n\t\t\t\t\treturn fmt.Errorf(\"mtime of key should be within 30 seconds, but got %s\", objs[1].Mtime().Sub(now))\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"list failed: %s\", err)\n\t\t\t}\n","sourceCodeStart":878,"sourceCodeEnd":914,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/cmd/objbench.go#L878-L914","documentation":"Raised in the objbench 'list objects' filesystem case: the first entry returned by the list must be the directory placeholder with an empty-string key, but a non-empty key was returned. Filesystem-style ObjectStorage implementations are required to include the \"\" entry representing the listed directory itself.","triggerScenarios":"listAll(ctx, blob, \"\", \"\", 2) returned 2 objects, but objs[0].Key() != \"\" — i.e. the backend ordered entries differently or did not synthesize the directory entry at position 0.","commonSituations":"A custom file backend that sorts entries lexicographically and puts a real object before the \"\" entry; a backend that never emits the directory placeholder; testing with leftover keys that sort before \"test\".","solutions":["Fix the backend's List to emit the directory entry \"\" first when listing without a prefix.","Clear the test directory of extra keys that could alter ordering.","Compare behavior with the reference file:// implementation in pkg/object and align it.","Pin/upgrade JuiceFS so the backend and objbench come from the same version.","Rerun objbench against a clean directory."],"exampleFix":"// before\nreturn sortedEntries, nil // \"\" entry may be missing or misordered\n// after\nentries := append([]Object{&entry{key: \"\", size: 0}}, sortedEntries...)\nreturn entries, nil","handlingStrategy":"type-guard","validationCode":"objs, _ := listAll(ctx, blob, \"\", \"\", 2)\nif len(objs) > 0 && objs[0].Key() != \"\" {\n    log.Printf(\"first entry is not the directory placeholder: %q\", objs[0].Key())\n}","typeGuard":"func isFirstDirEntry(objs []object.Object) bool {\n    return len(objs) > 0 && objs[0].Key() == \"\"\n}","tryCatchPattern":"objs, err := listAll(ctx, blob, \"\", \"\", 2)\nif err == nil && len(objs) > 0 && objs[0].Key() != \"\" {\n    // handle non-conformant backend: normalize or reject\n}","preventionTips":["Emit the \"\" directory entry first in custom List implementations.","Normalize keys identically in Put and List.","Use a clean test directory.","Compare against pkg/object file storage behavior."],"tags":["object-storage","list","filesystem","directory-entry"],"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"}