juicedata/juicefs · error

list should return 2 keys, but got %d

Error message

list should return 2 keys, but got %d

What it means

Raised in the objbench 'list objects' case for filesystem-backed stores (isFileSystem): listAll(ctx, blob, "", "", 2) must return exactly 2 entries — the mandatory directory entry for "" (size 0) plus the test object "test" — but a different number of entries was returned. This verifies that filesystem-style backends emulate listing-with-directory-entries correctly.

Source

Thrown at cmd/objbench.go:893

	runCase("delete non-exist", func(blob object.ObjectStorage) error {
		if err := blob.Delete(ctx, key); err != nil {
			return fmt.Errorf("deleting a non-existent object returns an error %v", err)
		}
		return nil
	})

	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 {

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Confirm the test directory/prefix is clean (no other keys beginning with the test prefix).
  2. If implementing a filesystem backend, ensure List returns the directory entry "" as the first object with size 0.
  3. Verify the backend honors the limit parameter the same way listAll accumulates pages.
  4. Check JuiceFS version — list semantics for file backends changed historically; upgrade to a consistent version.
  5. Rerun objbench on an empty temp directory to isolate.

Example fix

// before (custom fs backend list omits dir entry)
objs := []object.Object{fileObj}
// after
objs := []object.Object{&dirEntry{key: "", size: 0}, fileObj} // include "" entry first
Defensive patterns

Strategy: type-guard

Validate before calling

objs, err := listAll(ctx, blob, "", "", 2)
if err == nil && len(objs) != 2 {
    log.Printf("unexpected list length: %d", len(objs))
}

Type guard

func hasDirEntry(objs []object.Object) bool {
    return len(objs) > 0 && objs[0].Key() == "" && objs[0].Size() == 0
}

Try / catch

objs, err := listAll(ctx, blob, "", "", 2)
if err != nil {
    return err
}
if !hasDirEntry(objs) {
    log.Printf("backend does not synthesize directory entry; not filesystem-conformant")
}

Prevention

When it happens

Trigger: The test puts one object at `key` under a filesystem backend (e.g. file:// or sftp://), then lists with prefix "" marker "" limit 2 and receives != 2 objects — typically because the backend does not synthesize the empty-string directory entry, or leftover objects in the test prefix change the count.

Common situations: Custom filesystem-like ObjectStorage implementations that omit the "" directory placeholder; running against a shared/dirty directory containing other files; a limit/offset handling bug in the backend's List method.

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


AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06). Data as JSON: /api/errors/e614c262f68b38e0. Report an issue: GitHub.