juicedata/juicefs · error

list should return 1 keys, but got %d

Error message

list should return 1 keys, but got %d

What it means

In the non-filesystem branch of objbench's "list objects" case, `listAll(ctx, blob, "", "", 1)` must return exactly 1 key (the single "test" object put just before). This message means the backend returned a different number of keys for a maxKeys=1 list, violating list pagination/limit semantics.

Source

Thrown at cmd/objbench.go:925

				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)
			} else if len(objs) != 0 {
				return fmt.Errorf("list should not return anything, but got %d", len(objs))
			}
		} else {
			objs, err2 := listAll(ctx, blob, "", "", 1)
			if err2 == nil {
				if len(objs) != 1 {
					return fmt.Errorf("list should return 1 keys, but got %d", len(objs))
				}
				if objs[0].Key() != key {
					return fmt.Errorf("first key should be test, but got %s", objs[0].Key())
				}
				if objs[0].Size() != 5 {
					return fmt.Errorf("size of first key shold be 5, but got %v", objs[0].Size())
				}
				now := time.Now()
				if objs[0].Mtime().Before(now.Add(-30*time.Second)) || objs[0].Mtime().After(now.Add(time.Second*30)) {
					return fmt.Errorf("mtime of key should be within 30 seconds, but got %s", objs[0].Mtime().Sub(now))
				}
			} else {
				return fmt.Errorf("list failed: %s", err2)
			}

			objs, err2 = listAll(ctx, blob, "", "test2", 1)
			if err2 != nil {
				return fmt.Errorf("list failed: %s", err2)

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Run objbench against a clean, dedicated bucket so exactly one key matches.
  2. Fix the backend's List to respect the requested maxKeys (1 here) in a single page.
  3. Verify the earlier Put of key "test" succeeded before List is called.
  4. Check for stale objects with the bench key from previous runs and delete them.

Example fix

// backend List: honor limit
if len(result) > maxKeys { result = result[:maxKeys] }
Defensive patterns

Strategy: validation

Validate before calling

objs, _ := listAll(ctx, blob, "", "", 10)
if len(objs) != 1 {
    return fmt.Errorf("bucket not clean; got %d keys, expected 1", len(objs))
}

Prevention

When it happens

Trigger: `juicefs objbench` on a non-filesystem object storage that ignores the maxKeys limit and returns more objects, or returns zero keys despite the put succeeding, or lists leftover keys in a dirty bucket.

Common situations: Custom backend that ignores the `maxKeys`/limit parameter; shared bucket polluted with other keys; put failed silently or eventual consistency hiding the new key.

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/9ee126a908853a73. Report an issue: GitHub.