infiniflow/ragflow · error · CredentialExpiredError
Credential issue encountered ({error_code}).
Error message
Credential issue encountered ({error_code}). What it means
Raised by BlobStorageConnector.validate_connector_settings as the fallback credential branch: the probe failed with one of AccessDenied / InvalidAccessKeyId / SignatureDoesNotMatch, but neither the 403/AccessDenied condition (insufficient permissions) nor the 401/SignatureDoesNotMatch condition (invalid credentials) matched. The original S3 error code is embedded in the CredentialExpiredError message.
Source
Thrown at common/data_source/blob_connector.py:337
# 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"),
}
# Initialize connector
connector = BlobStorageConnector(
bucket_type=os.environ.get("BUCKET_TYPE") or "s3",
bucket_name=os.environ.get("BUCKET_NAME") or "yyboombucket",View on GitHub (pinned to 554fb1133a)
Solutions
- Re-verify the credential pair for correctness (key id exists, secret matches) even though the message is generic — read the embedded error_code
- If the provider is S3-compatible, test the same credentials with its own CLI (mc, rclone) to isolate status-code quirks
- Check system clock sync (NTP) — signing uses the timestamp, and skew can produce signature errors with unusual statuses
- Regenerate the key pair on the provider and update the connector config if the key is expired or revoked
Defensive patterns
Strategy: try-catch
Validate before calling
# isolate the cause before the connector does its opaque mapping
try:
s3.list_objects_v2(Bucket=bucket, MaxKeys=1)
except botocore.exceptions.ClientError as e:
code = e.response.get('Error', {}).get('Code')
status = e.response.get('ResponseMetadata', {}).get('HTTPStatusCode')
log.warning('probe failed code=%s status=%s', code, status) Try / catch
from common.data_source.exceptions import CredentialExpiredError, ConnectorValidationError
try:
connector.validate_connector_settings()
except CredentialExpiredError as e:
code = parse_embedded_code(e) # original S3 error code is in the message
if code == 'InvalidAccessKeyId':
rotate_credentials()
else:
raise Prevention
- Sync host clocks via NTP — signing skew produces odd status/code combinations that land in this branch
- For S3-compatible providers, smoke-test credentials with the provider CLI to learn its status-code quirks before wiring the connector
When it happens
Trigger: InvalidAccessKeyId with a non-403 status, or SignatureDoesNotMatch with a non-401 status — typical of S3-compatible providers (MinIO, Ceph, R2, OCI) that return nonstandard HTTP status codes with these AWS-style error codes. The connector conservatively assumes a credential problem.
Common situations: MinIO returning 403 SignatureDoesNotMatch when the secret is wrong (but the first branch catches AccessDenied-named codes at 403, so mismatched combinations fall through); clock skew breaking request signing against some providers; providers that map expired keys to odd statuses.
Related errors
- main() must be defined or exported.
- main() returned a non-JSON-serializable value.
- message.compileNotSupported
- Failed to fetch search detail
- Invalid SSH provider configuration.
AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15).
Data as JSON: /api/errors/20c1952cc7ed750c.
Report an issue: GitHub.