{"record":{"id":"4f117ee95a517c96","repo":"JuliusBrussee/caveman","slug":"objectstore-delete-q-w","errorCode":null,"errorMessage":"objectstore: delete %q: %w","messagePattern":"objectstore: delete %q: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/objectstore/objectstore.go","lineNumber":308,"sourceCode":"\tif maxBytes <= 0 {\n\t\tmaxBytes = 64 << 20\n\t}\n\tbody, err := io.ReadAll(io.LimitReader(obj, maxBytes+1))\n\tif err != nil {\n\t\tif minio.ToErrorResponse(err).Code == \"NoSuchKey\" {\n\t\t\treturn nil, ErrNotFound\n\t\t}\n\t\treturn nil, fmt.Errorf(\"objectstore: read %q: %w\", key, err)\n\t}\n\tif int64(len(body)) > maxBytes {\n\t\treturn nil, ErrTooLarge\n\t}\n\treturn body, nil\n}\n\nfunc (m *minioStore) Delete(ctx context.Context, key string) error {\n\tif err := m.client.RemoveObject(ctx, m.bucket, key, minio.RemoveObjectOptions{}); err != nil {\n\t\treturn fmt.Errorf(\"objectstore: delete %q: %w\", key, err)\n\t}\n\treturn nil\n}\n\nfunc (m *minioStore) DeleteAllVersions(ctx context.Context, key string) error {\n\treturn m.deleteVersions(ctx, key, true)\n}\n\nfunc (m *minioStore) DeletePrefixAllVersions(ctx context.Context, prefix string) error {\n\treturn m.deleteVersions(ctx, prefix, false)\n}\n\nfunc (m *minioStore) deleteVersions(ctx context.Context, keyOrPrefix string, exact bool) error {\n\tfound := false\n\tfor obj := range m.client.ListObjects(ctx, m.bucket, minio.ListObjectsOptions{\n\t\tPrefix: keyOrPrefix, Recursive: true, WithVersions: true,\n\t}) {\n\t\tif obj.Err != nil {","sourceCodeStart":290,"sourceCodeEnd":326,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/shared/platform/objectstore/objectstore.go#L290-L326","documentation":"minioStore.Delete wraps a failure from client.RemoveObject. It means the object store rejected or failed the removal request — not that the key was absent (RemoveObject is idempotent and typically succeeds for missing keys). The key is embedded in the message and the underlying error is preserved with %w.","triggerScenarios":"Calling Delete(ctx, key) (directly or via deleteVersions from DeleteAllVersions) when RemoveObject returns a non-nil error: permission denied on the bucket, network failure, wrong bucket name, read-only bucket policy, or storage backend outage.","commonSituations":"IAM/bucket policy lacking s3:DeleteObject; pointing at a versioned bucket where policies block deletes; transient MinIO/S3 5xx; misconfigured bucket after environment change; Docker-compose MinIO restarted with different credentials.","solutions":["Check the wrapped error via minio.ToErrorResponse for AccessDenied and fix bucket/IAM policy to allow s3:DeleteObject.","Retry on transient 5xx/network errors with backoff.","Verify the bucket name and endpoint in the store configuration.","Confirm credentials are valid and not expired (mc admin or console).","Check bucket versioning/retention (object lock) rules that may block removal."],"exampleFix":"// before\nerr := store.Delete(ctx, key)\n// after\nif err := store.Delete(ctx, key); err != nil {\n    var minioErr minio.ErrorResponse\n    if errors.As(err, &minioErr) && minioErr.Code == \"AccessDenied\" {\n        return fmt.Errorf(\"delete %s: missing s3:DeleteObject permission: %w\", key, err)\n    }\n    return err\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := store.Delete(ctx, key); err != nil {\n    var mr minio.ErrorResponse\n    if errors.As(err, &mr) && mr.Code == \"AccessDenied\" {\n        // surface as config/permission problem, do not retry\n    }\n    return err\n}","preventionTips":["Provision IAM with s3:DeleteObject before deploying delete paths.","Smoke-test delete permissions against the real bucket in CI.","Treat deletes as idempotent; don't pre-check existence.","Alert on AccessDenied codes — they indicate policy drift, not transient faults."],"tags":["object-storage","delete","minio","permissions"],"backgroundTag":"database-write-failed","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}