{"record":{"id":"0181bb61dad2529f","repo":"elunez/eladmin","slug":"error-0181bb","errorCode":null,"errorMessage":"检查存储桶时出错: {}","messagePattern":"检查存储桶时出错: (.+?)","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"eladmin-tools/src/main/java/me/zhengjie/service/impl/S3StorageServiceImpl.java","lineNumber":231,"sourceCode":"     * 检查云存储桶是否存在\n     * @param bucketName 存储桶名称\n     */\n    @SuppressWarnings({\"all\"})\n    private boolean bucketExists(String bucketName) {\n        try {\n            HeadBucketRequest headBucketRequest = HeadBucketRequest.builder()\n                    .bucket(bucketName)\n                    .build();\n            s3Client.headBucket(headBucketRequest);\n            return true;\n        } catch (S3Exception e) {\n            // 如果状态码是 404 (Not Found), 说明存储桶不存在\n            if (e.statusCode() == 404) {\n                log.error(\"存储桶 '{}' 不存在。\", bucketName);\n                return false;\n            }\n            // 其他异常 (如 403 Forbidden) 说明存在问题，但不能断定它不存在\n            throw new BadRequestException(\"检查存储桶时出错: \" + e.awsErrorDetails().errorMessage());\n        }\n    }\n\n    /**\n     * 创建云存储桶\n     * @param bucketName 存储桶名称\n     */\n    private boolean createBucket(String bucketName) {\n        try {\n            // 使用 S3Waiter 等待存储桶创建完成\n            S3Waiter s3Waiter = s3Client.waiter();\n            CreateBucketRequest bucketRequest = CreateBucketRequest.builder()\n                    .bucket(bucketName)\n                    .acl(BucketCannedACL.PRIVATE)\n                    .build();\n            s3Client.createBucket(bucketRequest);\n            // 等待直到存储桶创建完成\n            HeadBucketRequest bucketRequestWait = HeadBucketRequest.builder()","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/elunez/eladmin/blob/55fbf705956949697dbd68bf9003776609d3d029/eladmin-tools/src/main/java/me/zhengjie/service/impl/S3StorageServiceImpl.java#L213-L249","documentation":"BadRequestException thrown from bucketExists(bucketName) when the S3 headBucket call fails with an S3Exception whose status is NOT 404 — i.e. the SDK reached S3 but the request was rejected (classic: 403 credentials wrong or no s3:ListBuckets/HeadBucket permission; also 301 wrong-region). The method deliberately returns false only for 404; every other failure bubbles up as this error with the AWS detail appended.","triggerScenarios":"Any S3 storage operation (upload, deleteAll, download) triggering bucketExists while the configured credentials are invalid/expired, the IAM principal lacks HeadBucket rights, or the endpoint/region in amzS3Config points elsewhere (301 redirect treated as exception).","commonSituations":"Rotated or deleted access keys not updated in the admin S3 config; least-privilege IAM user without s3:ListBucket/HeadBucket; wrong region or a MinIO endpoint requiring path-style while configured as virtual-host; clock skew causing signature errors (403).","solutions":["Check the appended AWS message: 'AccessDenied' -> fix credentials/permissions; 'PermanentRedirect'/'region' -> fix endpoint/region.","Re-enter valid accessKey/secretKey in the S3 config and confirm the IAM user can head the bucket (aws s3api head-bucket --bucket <name>).","Grant s3:ListBucket on the bucket (or s3:ListAllMyBuckets) plus s3:HeadBucket as needed.","For MinIO/compatible stores, use the correct endpoint URL and path-style access in the client config.","Verify server clock sync (signature v4 is time-sensitive)."],"exampleFix":"// before\ncatch (S3Exception e) {\n    if (e.statusCode() == 404) {\n        log.error(\"存储桶 '{}' 不存在。\", bucketName);\n        return false;\n    }\n    throw new BadRequestException(\"检查存储桶时出错: \" + e.awsErrorDetails().errorMessage());\n}\n\n// after: name the likely cause by status code\ncatch (S3Exception e) {\n    if (e.statusCode() == 404) {\n        return false;\n    }\n    if (e.statusCode() == 403) {\n        throw new BadRequestException(\"无权访问存储桶（凭证错误或缺少权限）: \" + e.awsErrorDetails().errorMessage());\n    }\n    throw new BadRequestException(\"检查存储桶时出错: \" + e.awsErrorDetails().errorMessage());\n}","handlingStrategy":"try-catch","validationCode":"// config-time validation: prove credentials can head the bucket\ntry {\n    s3Client.headBucket(HeadBucketRequest.builder().bucket(bucketName).build());\n} catch (S3Exception e) {\n    if (e.statusCode() == 403) throw new BadRequestException(\"S3 凭证无效或缺少权限\");\n    if (e.statusCode() == 301) throw new BadRequestException(\"S3 region/endpoint 配置错误\");\n}","typeGuard":null,"tryCatchPattern":"try { s3StorageService.upload(file); } catch (BadRequestException e) { if (e.getMessage().startsWith(\"检查存储桶时出错\")) { /* 403/301 class: fix credentials or endpoint; retrying cannot help */ } }","preventionTips":["Run a head-bucket smoke test when saving S3 credentials in the admin UI.","Rotate keys via the config page promptly; expired keys surface exactly here.","Keep server clocks NTP-synced — SigV4 rejects skewed timestamps as 403."],"tags":["s3","aws-sdk-v2","iam","credentials","region"],"backgroundTag":null,"analyzedSha":"55fbf705956949697dbd68bf9003776609d3d029","analyzedAt":"2026-08-14T11:56:12.758Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}