juicedata/juicefs · error
expect err is not nil
Error message
expect err is not nil
What it means
This error comes from the 'delete an object' objbench case when blob.Head(ctx, key) unexpectedly SUCCEEDS after the key was deleted. The test expects Head to return an error (object not found) once the object is deleted; a nil error means the delete did not actually take effect or the backend is not reporting absence. objbench throws it to flag a backend that violates the expected delete visibility semantics.
Source
Thrown at cmd/objbench.go:867
return fmt.Errorf("failed to head object %s", err)
} else {
if h.Key() != key {
return fmt.Errorf("expected key 'test' but got %s", h.Key())
}
}
return nil
})
runCase("delete an object", 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)
}
if err := blob.Delete(ctx, key); err != nil {
return fmt.Errorf("delete failed: %s", err)
}
if _, err := blob.Head(ctx, key); err == nil {
return fmt.Errorf("expect err is not nil")
}
if err := blob.Delete(ctx, key); err != nil {
return fmt.Errorf("delete not existed: %v", err)
}
return nil
})
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 {View on GitHub (pinned to c9a67b23e8)
Solutions
- Inspect the custom/underlying ObjectStorage implementation's Delete and Head for swallowed errors or stale caching.
- Disable or shorten lookup caches (e.g. --attr-cache, dir entry cache) when benchmarking filesystem-backed stores.
- Confirm the delete actually hits the backend (list the bucket after the run).
- If the backend has asynchronous delete semantics, that backend is non-conformant for JuiceFS; fix the implementation.
- Rerun objbench with a clean bucket/prefix to rule out leftover objects with the same key.
Example fix
// before: Head succeeds after Delete
if _, err := blob.Head(ctx, key); err == nil {
return fmt.Errorf("expect err is not nil")
}
// after (in the backend implementation): propagate the removal
func (s *store) Delete(ctx context.Context, key string) error {
return os.Remove(s.path(key)) // do NOT swallow ENOENT silently
} Defensive patterns
Strategy: try-catch
Validate before calling
// after delete, confirm absence out-of-band before asserting Head fails _, err := blob.Head(ctx, key) deleted := err != nil
Try / catch
if _, err := blob.Head(ctx, key); err == nil {
log.Printf("object still present after delete; check backend delete semantics/caches")
} Prevention
- Test custom ObjectStorage implementations against the reference objbench suite before use.
- Disable attr/entry caches when benchmarking file-backed stores.
- Use versioning-disabled buckets for delete tests.
- Clean the test prefix to avoid stale keys.
When it happens
Trigger: After Put + successful Delete of the test key, blob.Head(ctx, key) returns a nil error and a valid object header — i.e. the object is still listable/headable. Causes include asynchronous delete semantics, a cached/virtual backend (e.g. mem or a buggy filesystem wrapper) that still reports the key, or the delete silently no-oping.
Common situations: Testing a custom ObjectStorage implementation that doesn't propagate deletes; a filesystem backend where unlink failed but Delete swallowed the error; eventual-consistency or caching layers (dir lookup cache) serving a stale entry; testing against a bucket with versioning where Head resolves to an old version.
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
- ErrNotSUP
- failed to get the first byte:, expect "h", but got %q, error
- failed to get the last byte: expect "o", but got %q, error:
- failed to get the last three bytes: expect "llo", but got %q
- failed to get two bytes: expect "ll", but got %q, error: %s
AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06).
Data as JSON: /api/errors/b2a557e8f5df04b8.
Report an issue: GitHub.