juicedata/juicefs · error
deleting a non-existent object returns an error %v
Error message
deleting a non-existent object returns an error %v
What it means
This error is raised by the dedicated 'delete non-exist' objbench case when a backend returns an error for deleting an object that was never created. JuiceFS expects every ObjectStorage implementation to make Delete idempotent — deleting a nonexistent key must return nil. The message wraps the backend's error (typically a 404 or ENOENT).
Source
Thrown at cmd/objbench.go:878
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 {
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())View on GitHub (pinned to c9a67b23e8)
Solutions
- Make the backend's Delete return nil on not-found (map 404/NoSuchKey/ENOENT to success), matching S3 and POSIX semantics.
- Check the wrapped error text to identify which backend call returned it.
- If testing a custom store, add explicit handling for the vendor's not-found error code.
- Add a unit/regression test asserting Delete of a missing key returns nil.
- Rerun `juicefs objbench <storage-url>` to confirm.
Example fix
// before
return os.Remove(path) // ENOENT surfaces to caller
// after
if err := os.Remove(path); err != nil && !os.IsNotExist(err) {
return err
}
return nil Defensive patterns
Strategy: validation
Validate before calling
// pre-check existence if the backend lacks idempotent delete
if _, err := blob.Head(ctx, key); err == nil {
if err := blob.Delete(ctx, key); err != nil { return err }
} Try / catch
err := blob.Delete(ctx, key)
if err != nil && isNotFound(err) {
return nil // acceptable: object already absent
} Prevention
- Choose backends with S3-compatible idempotent delete semantics.
- Wrap third-party SDKs to swallow not-found delete errors.
- Run objbench 'delete non-exist' before production use.
- Keep vendor SDK versions updated for semantics changes.
When it happens
Trigger: Directly calling blob.Delete(ctx, key) for a key that does not exist in the bucket, and the backend returns a not-found error instead of treating the delete as a no-op.
Common situations: Custom or vendor-specific ObjectStorage implementations that surface 404s; testing against S3-compatible services (e.g. some MinIO configurations, Ceph gateways, or private cloud stores) that return NoSuchKey on delete; filesystem-backed stores leaking os.Remove's ENOENT.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- delete not existed: %v
- delete failed: %s
- 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:
AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06).
Data as JSON: /api/errors/09ea508e92990e04.
Report an issue: GitHub.