infiniflow/ragflow · error · InsufficientPermissionsError
Insufficient permissions to list objects in bucket '{self.bu
Error message
Insufficient permissions to list objects in bucket '{self.bucket_name}'. Please check your bucket policy and/or IAM policy. What it means
Raised by BlobStorageConnector.validate_connector_settings when the list_objects_v2 probe fails with error code AccessDenied, InvalidAccessKeyId, or SignatureDoesNotMatch AND (status 403 or code == 'AccessDenied'). This branch means the credentials authenticated but the identity lacks s3:ListBucket permission on the bucket, so InsufficientPermissionsError is raised with guidance to check bucket and IAM policy.
Source
Thrown at common/data_source/blob_connector.py:333
if not self.bucket_name:
raise ConnectorValidationError("No bucket name was provided in connector settings.")
try:
# Lightweight validation step
self.s3_client.list_objects_v2(Bucket=self.bucket_name, Prefix=self.prefix, MaxKeys=1)
except Exception as e:
error_code = getattr(e, "response", {}).get("Error", {}).get("Code", "")
status_code = getattr(e, "response", {}).get("ResponseMetadata", {}).get("HTTPStatusCode")
# Common S3 error scenarios
if error_code in [
"AccessDenied",
"InvalidAccessKeyId",
"SignatureDoesNotMatch",
]:
if status_code == 403 or error_code == "AccessDenied":
raise InsufficientPermissionsError(f"Insufficient permissions to list objects in bucket '{self.bucket_name}'. Please check your bucket policy and/or IAM policy.")
if status_code == 401 or error_code == "SignatureDoesNotMatch":
raise CredentialExpiredError("Provided blob storage credentials appear invalid or expired.")
raise CredentialExpiredError(f"Credential issue encountered ({error_code}).")
if error_code == "NoSuchBucket" or status_code == 404:
raise ConnectorValidationError(f"Bucket '{self.bucket_name}' does not exist or cannot be found.")
raise ConnectorValidationError(f"Unexpected S3 client error (code={error_code}, status={status_code}): {e}")
if __name__ == "__main__":
# Example usage
credentials_dict = {
"aws_access_key_id": os.environ.get("AWS_ACCESS_KEY_ID"),
"aws_secret_access_key": os.environ.get("AWS_SECRET_ACCESS_KEY"),
}
View on GitHub (pinned to 554fb1133a)
Solutions
- Add s3:ListBucket on the specific bucket (and s3:GetObject on bucket/*) to the IAM policy of the key's owner
- If the bucket is in another account, add a bucket-policy statement allowing s3:ListBucket for the caller's ARN
- Check for explicit Deny statements in IAM, bucket policy, SCPs, or VPC endpoint policies that override the Allow
- For S3-compatible stores, grant the key's policy the listing permission on the bucket (e.g. MinIO 'readlist' or console 'readwrite' scoped policy)
Example fix
# before (IAM policy — download only)
{
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::docs-bucket/*"]
}
# after
{
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::docs-bucket/*"]
},
{
"Effect": "Allow",
"Action": ["s3:ListBucket"],
"Resource": ["arn:aws:s3:::docs-bucket"]
} Defensive patterns
Strategy: try-catch
Validate before calling
import boto3
sts = boto3.client('sts', aws_access_key_id=k, aws_secret_access_key=s)
identity = sts.get_caller_identity() # cheap auth check
# then verify ListBucket with an explicit dry probe:
s3 = boto3.client('s3', aws_access_key_id=k, aws_secret_access_key=s)
try:
s3.list_objects_v2(Bucket=bucket, MaxKeys=1)
except s3.exceptions.ClientError as e:
if e.response['Error']['Code'] in ('AccessDenied', '403'):
raise PermissionError('need s3:ListBucket on ' + bucket) from e Try / catch
from common.data_source.exceptions import InsufficientPermissionsError
try:
connector.validate_connector_settings()
except InsufficientPermissionsError as e:
alert_ops(f'IAM fix needed: {e}') # non-retryable config problem
raise Prevention
- Provision indexing keys with s3:ListBucket on arn:aws:s3:::bucket AND s3:GetObject on arn:aws:s3:::bucket/* from day one
- Check bucket policies and SCPs for explicit Deny on ListBucket before shipping a least-privilege key
When it happens
Trigger: An IAM user/role with GetObject but no ListBucket permission running validate_connector_settings; a bucket policy that explicitly denies s3:ListBucket for the caller's principal; an SCP or VPC endpoint policy restricting ListBucket; also AccessDenied from S3-compatible providers when the key is scoped to a different bucket.
Common situations: Least-privilege IAM keys created for read/download only; bucket owned by another AWS account with a bucket policy missing a ListBucket statement for the caller; MinIO/Ops role without read:list access; confusion between ListBucket (bucket-level) and GetObject (object-level) permissions.
Related errors
- Provided blob storage credentials appear invalid or expired.
- Bucket '{self.bucket_name}' does not exist or cannot be foun
- Unexpected S3 client error (code={error_code}, status={statu
- Insufficient permissions to access Confluence resources (HTT
- Your Dropbox token does not have sufficient permissions.
AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15).
Data as JSON: /api/errors/846efaae8e3eb645.
Report an issue: GitHub.