juicedata/juicefs · error
first object size should be 0, but got %d
Error message
first object size should be 0, but got %d
What it means
Raised in the objbench 'list objects' filesystem case: the first listed entry (the directory placeholder for "") must have Size() == 0, but a nonzero size was returned. This asserts that filesystem backends report directory entries with zero size, matching how object listings emulate directories.
Source
Thrown at cmd/objbench.go:899
})
runCase("list objects", func(blob object.ObjectStorage) error {
br := []byte("hello")
if err := blob.Put(ctx, key, bytes.NewReader(br)); err != nil {
return fmt.Errorf("put object failed: %s", err)
}
defer blob.Delete(ctx, key) //nolint:errcheck
if isFileSystem {
objs, err := listAll(ctx, blob, "", "", 2)
if err == nil {
if len(objs) != 2 {
return fmt.Errorf("list should return 2 keys, but got %d", len(objs))
}
if objs[0].Key() != "" {
return fmt.Errorf("first key should be empty string, but got %s", objs[0].Key())
}
if objs[0].Size() != 0 {
return fmt.Errorf("first object size should be 0, but got %d", objs[0].Size())
}
if objs[1].Key() != key {
return fmt.Errorf("first key should be test, but got %s", objs[1].Key())
}
if objs[1].Size() != 5 {
return fmt.Errorf("size of first key shold be 5, but got %v", objs[1].Size())
}
now := time.Now()
if objs[1].Mtime().Before(now.Add(-30*time.Second)) || objs[1].Mtime().After(now.Add(time.Second*30)) {
return fmt.Errorf("mtime of key should be within 30 seconds, but got %s", objs[1].Mtime().Sub(now))
}
} else {
return fmt.Errorf("list failed: %s", err)
}
objs, err = listAll(ctx, blob, "", "test2", 1)
if err != nil {
return fmt.Errorf("list failed: %s", err)View on GitHub (pinned to c9a67b23e8)
Solutions
- In the backend's List, hardcode Size()=0 for synthesized directory entries instead of the directory's stat size.
- Ensure the size field is reset/zeroed for placeholder entries.
- Test against the reference file:// backend behavior in pkg/object.
- Clean the test directory of stray keys that could be mistaken for the dir entry.
- Rerun objbench.
Example fix
// before
return &entry{key: "", size: fi.Size()}, nil // 4096 for dirs
// after
return &entry{key: "", size: 0}, nil // dir entry must be size 0 Defensive patterns
Strategy: type-guard
Validate before calling
objs, _ := listAll(ctx, blob, "", "", 2)
if len(objs) > 0 && objs[0].Key() == "" && objs[0].Size() != 0 {
log.Printf("dir entry has nonzero size: %d", objs[0].Size())
} Type guard
func isZeroSizeDirEntry(o object.Object) bool {
return o.Key() == "" && o.Size() == 0
} Try / catch
if o := objs[0]; o.Key() == "" && o.Size() != 0 {
log.Printf("backend reports dir size %d; treat as 0", o.Size())
} Prevention
- Hardcode size 0 for synthesized directory entries.
- Do not stat directories for list entry sizes.
- Unit-test List output shapes for file backends.
- Run objbench before deploying custom stores.
When it happens
Trigger: After listAll returns 2 entries with the correct keys, objs[0].Size() != 0 — the backend filled in a real byte size (e.g. directory stat size like 4096, or an object's size) for the directory entry.
Common situations: A custom file backend that calls os.Stat on the directory and reports its allocated size; a backend that reuses a struct with a stale size field; listing a prefix that matches a real object with the same path.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- size of first key shold be 5, but got %v
- list should return 2 keys, but got %d
- first key should be empty string, but got %s
- first key should be test, but got %s
- list failed: %s
AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06).
Data as JSON: /api/errors/d7f25ef6f4b3f792.
Report an issue: GitHub.