infiniflow/ragflow · critical · ConnectorMissingCredentialError
Cloudflare R2
Error message
Cloudflare R2
What it means
BlobConnector.load_credentials for bucket_type R2 requires all of r2_access_key_id, r2_secret_access_key, and account_id; missing any one raises ConnectorMissingCredentialError('Cloudflare R2').
Source
Thrown at common/data_source/blob_connector.py:86
# Populated by list_keys() so a subsequent get_value(key) can find the
# raw S3 object metadata (LastModified, ETag, Key, Size) without a second
# head_object call. Lifetime is one list_keys() pass.
self._listing_cache: dict[str, dict[str, Any]] = {}
self._filename_counts: dict[str, int] = {}
def set_allow_images(self, allow_images: bool) -> None:
"""Set whether to process images"""
logging.info(f"Setting allow_images to {allow_images}.")
self._allow_images = allow_images
def load_credentials(self, credentials: dict[str, Any]) -> dict[str, Any] | None:
"""Load credentials"""
logging.debug(f"Loading credentials for {self.bucket_name} of type {self.bucket_type}")
# Validate credentials
if self.bucket_type == BlobType.R2:
if not all(credentials.get(key) for key in ["r2_access_key_id", "r2_secret_access_key", "account_id"]):
raise ConnectorMissingCredentialError("Cloudflare R2")
elif self.bucket_type == BlobType.S3:
authentication_method = credentials.get("authentication_method", "access_key")
if authentication_method == "access_key":
if not all(credentials.get(key) for key in ["aws_access_key_id", "aws_secret_access_key"]):
raise ConnectorMissingCredentialError("Amazon S3")
elif authentication_method == "iam_role":
if not credentials.get("aws_role_arn"):
raise ConnectorMissingCredentialError("Amazon S3 IAM role ARN is required")
elif authentication_method == "assume_role":
pass
else:
raise ConnectorMissingCredentialError("Unsupported S3 authentication method")
View on GitHub (pinned to 554fb1133a)
Solutions
- Generate an R2 API token in the Cloudflare dashboard and copy the Access Key ID, Secret Access Key, and the account ID
- Supply all three in the credentials dict with exact key names
- Re-run load_credentials to confirm it passes
Example fix
// before
creds = {"r2_access_key_id": "x", "r2_secret_access_key": "y"}
// after
creds = {"r2_access_key_id": "x", "r2_secret_access_key": "y", "account_id": "a1b2c3"} Defensive patterns
Strategy: validation
Validate before calling
R2_KEYS = ("r2_access_key_id", "r2_secret_access_key", "account_id")
if not all(creds.get(k) for k in R2_KEYS):
missing = [k for k in R2_KEYS if not creds.get(k)]
raise ValueError(f"missing R2 credentials: {missing}") Type guard
def is_r2_cred_dict(x) -> bool:
"""True when x has all non-empty Cloudflare R2 credential fields."""
return isinstance(x, dict) and all(
isinstance(x.get(k), str) and x[k].strip() for k in ("r2_access_key_id", "r2_secret_access_key", "account_id")
) Try / catch
try:
blob.load_credentials(creds)
except ConnectorMissingCredentialError as e:
if "Cloudflare R2" in str(e):
creds = regenerate_r2_token_in_dashboard_and_refill()
blob.load_credentials(creds) Prevention
- Copy all three values from the R2 'Manage API Tokens' page in one sitting
- Persist account_id alongside the keys — it is required, not optional
- Validate the credential dict shape before saving the connector
When it happens
Trigger: R2 connector config where any of the three keys is absent or empty during load_credentials.
Common situations: Forgotten account_id (it is part of the S3 endpoint but also validated separately); token created in R2 console but keys not copied fully; key name typos.
Related errors
- Azure Blob: connection_string is required for the connection
- Azure Blob: account_name and account_key are required for th
- Amazon S3
- Google Cloud Storage
- Oracle Cloud Infrastructure
AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15).
Data as JSON: /api/errors/bf1ac1a6ebcad9d9.
Report an issue: GitHub.