{"record":{"id":"d0e2d177fa411a5d","repo":"OrchardCMS/OrchardCore","slug":"error-deleting-file-path-ex-message","errorCode":null,"errorMessage":"Error deleting file '${path}': ${ex.Message}","messagePattern":"Error deleting file '(.+?)': (.+?)","errorType":"exception","errorClass":"FileStoreException","httpStatus":null,"severity":"error","filePath":"src/OrchardCore/OrchardCore.FileStorage.AmazonS3/AwsFileStorage.cs","lineNumber":155,"sourceCode":"    public async Task<bool> TryDeleteFileAsync(string path)\n    {\n        try\n        {\n            var response = await _amazonS3Client.DeleteObjectAsync(new DeleteObjectRequest\n            {\n                BucketName = _options.BucketName,\n                Key = this.Combine(_basePrefix, path),\n            });\n\n            return response.IsDeleteSuccessful();\n        }\n        catch (AmazonS3Exception ex) when (ex.StatusCode == HttpStatusCode.NotFound)\n        {\n            return false;\n        }\n        catch (AmazonS3Exception ex)\n        {\n            throw new FileStoreException($\"Error deleting file '{path}': {ex.Message}\", ex);\n        }\n    }\n\n    public async Task<bool> TryDeleteDirectoryAsync(string path)\n    {\n        if (string.IsNullOrWhiteSpace(path))\n        {\n            throw new FileStoreException(\"Cannot delete root directory.\");\n        }\n\n        var listObjectsResponse = await _amazonS3Client.ListObjectsV2Async(new ListObjectsV2Request\n        {\n            BucketName = _options.BucketName,\n            Prefix = NormalizePrefix(this.Combine(_basePrefix, path)),\n        });\n\n        if (listObjectsResponse.S3Objects?.Count > 0)\n        {","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/OrchardCMS/OrchardCore/blob/4306c0717fe573f6fca1b4955909ddab6a192807/src/OrchardCore/OrchardCore.FileStorage.AmazonS3/AwsFileStorage.cs#L137-L173","documentation":"AwsFileStorage.TryDeleteFileAsync wraps unexpected AmazonS3Exception failures in FileStoreException. A 404 is treated as 'file already gone' (returns false); any other S3 failure — permissions, throttling, connectivity — throws this message naming the path, with the original exception as InnerException. It is also reachable indirectly via MoveFileAsync when the target deletion fails.","triggerScenarios":"Calling TryDeleteFileAsync(path) (or MoveFileAsync which calls it) when DeleteObject fails with a non-404 AmazonS3Exception: AccessDenied, invalid credentials, throttling, or a misconfigured bucket.","commonSituations":"IAM policy lacking s3:DeleteObject on the prefix; read-only media credentials; S3 503 SlowDown during bulk deletes; bucket region mismatch after migration.","solutions":["Grant s3:DeleteObject on the bucket/prefix to the configured IAM credentials","Verify bucket/region/credentials in the Amazon S3 media settings and test delete manually","Check the InnerException's ErrorCode for the precise AWS cause","Add retry/backoff for throttling errors before surfacing the failure"],"exampleFix":"// before\nawait fileStore.MoveFileAsync(src, dst); // delete of src failed inside\n// after\ntry { await fileStore.MoveFileAsync(src, dst); }\ncatch (FileStoreException ex) { _logger.LogError(ex.InnerException, \"Delete failed for {Path}: {Code}\", src, (ex.InnerException as AmazonS3Exception)?.ErrorCode); }","handlingStrategy":"try-catch","validationCode":"// pre-flight delete permission check:\nawait _s3.PutObjectAsync(new PutObjectRequest { BucketName = bucket, Key = probeKey, ContentBody = \"probe\" });\nawait _s3.DeleteObjectAsync(new DeleteObjectRequest { BucketName = bucket, Key = probeKey });","typeGuard":"bool IsAccessDenied(FileStoreException ex) => ex.InnerException is AmazonS3Exception s3 && s3.ErrorCode == \"AccessDenied\";","tryCatchPattern":"try { deleted = await fileStore.TryDeleteFileAsync(path); } catch (FileStoreException ex) when (ex.InnerException is AmazonS3Exception s3 && s3.StatusCode != HttpStatusCode.NotFound) { _logger.LogError(ex, \"Delete failed for {Path}: {Code}\", path, s3.ErrorCode); }","preventionTips":["Grant s3:DeleteObject on the bucket/prefix to the configured credentials","Test MoveFileAsync paths — the delete inside it can throw too","Enable retries for throttling during bulk deletes","Monitor the inner AmazonS3Exception ErrorCode in logs"],"tags":["aws","s3","file-storage","permissions","io"],"backgroundTag":"file-write-failed","analyzedSha":"4306c0717fe573f6fca1b4955909ddab6a192807","analyzedAt":"2026-09-13T17:41:05.024Z","contentChangedAt":"2026-09-13T17:41:05.024Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}