{"record":{"id":"09ea508e92990e04","repo":"juicedata/juicefs","slug":"deleting-a-non-existent-object-returns-an-error-v","errorCode":null,"errorMessage":"deleting a non-existent object returns an error %v","messagePattern":"deleting a non-existent object returns an error (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/objbench.go","lineNumber":878,"sourceCode":"\t\tif err := blob.Put(ctx, key, bytes.NewReader(br)); err != nil {\n\t\t\treturn fmt.Errorf(\"put object failed: %s\", err)\n\t\t}\n\t\tif err := blob.Delete(ctx, key); err != nil {\n\t\t\treturn fmt.Errorf(\"delete failed: %s\", err)\n\t\t}\n\t\tif _, err := blob.Head(ctx, key); err == nil {\n\t\t\treturn fmt.Errorf(\"expect err is not nil\")\n\t\t}\n\n\t\tif err := blob.Delete(ctx, key); err != nil {\n\t\t\treturn fmt.Errorf(\"delete not existed: %v\", err)\n\t\t}\n\t\treturn nil\n\t})\n\n\trunCase(\"delete non-exist\", func(blob object.ObjectStorage) error {\n\t\tif err := blob.Delete(ctx, key); err != nil {\n\t\t\treturn fmt.Errorf(\"deleting a non-existent object returns an error %v\", err)\n\t\t}\n\t\treturn nil\n\t})\n\n\trunCase(\"list objects\", func(blob object.ObjectStorage) error {\n\t\tbr := []byte(\"hello\")\n\t\tif err := blob.Put(ctx, key, bytes.NewReader(br)); err != nil {\n\t\t\treturn fmt.Errorf(\"put object failed: %s\", err)\n\t\t}\n\t\tdefer blob.Delete(ctx, key) //nolint:errcheck\n\t\tif isFileSystem {\n\t\t\tobjs, err := listAll(ctx, blob, \"\", \"\", 2)\n\t\t\tif err == nil {\n\t\t\t\tif len(objs) != 2 {\n\t\t\t\t\treturn fmt.Errorf(\"list should return 2 keys, but got %d\", len(objs))\n\t\t\t\t}\n\t\t\t\tif objs[0].Key() != \"\" {\n\t\t\t\t\treturn fmt.Errorf(\"first key should be empty string, but got %s\", objs[0].Key())","sourceCodeStart":860,"sourceCodeEnd":896,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/cmd/objbench.go#L860-L896","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nreturn os.Remove(path) // ENOENT surfaces to caller\n// after\nif err := os.Remove(path); err != nil && !os.IsNotExist(err) {\n    return err\n}\nreturn nil","handlingStrategy":"validation","validationCode":"// pre-check existence if the backend lacks idempotent delete\nif _, err := blob.Head(ctx, key); err == nil {\n    if err := blob.Delete(ctx, key); err != nil { return err }\n}","typeGuard":null,"tryCatchPattern":"err := blob.Delete(ctx, key)\nif err != nil && isNotFound(err) {\n    return nil // acceptable: object already absent\n}","preventionTips":["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."],"tags":["object-storage","delete","idempotency","benchmark"],"backgroundTag":"resource-not-found","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}