infiniflow/ragflow · error · CredentialExpiredError
Provided blob storage credentials appear invalid or expired.
Error message
Provided blob storage credentials appear invalid or expired.
What it means
Raised by BlobStorageConnector.validate_connector_settings when the probe request fails with error code InvalidAccessKeyId, or SignatureDoesNotMatch with a 401, i.e. the credentials themselves are bad rather than merely under-permissioned. SignatureDoesNotMatch means the secret does not match the access key id; InvalidAccessKeyId means the access key id does not exist (or was rotated/deleted). Wrapped as CredentialExpiredError with a 'invalid or expired' message.
Source
Thrown at common/data_source/blob_connector.py:335
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"),
}
# Initialize connector
connector = BlobStorageConnector(View on GitHub (pinned to 554fb1133a)
Solutions
- Re-enter the access key id and secret exactly, with no leading/trailing whitespace or newlines
- If the key was rotated or deleted, generate a new pair and update the connector credential config
- Verify with a direct CLI test: aws s3 ls s3://<bucket> --endpoint-url <ep> using the same credentials
- Confirm the key pair belongs to the same account/tenancy as the bucket
Example fix
# before
creds = {
'aws_access_key_id': 'AKIA...\n', # trailing newline from a file read
'aws_secret_access_key': secret,
}
# after
creds = {
'aws_access_key_id': open(key_file).read().strip(),
'aws_secret_access_key': open(sec_file).read().strip(),
} Defensive patterns
Strategy: try-catch
Validate before calling
key = credentials['aws_access_key_id'].strip()
secret = credentials['aws_secret_access_key'].strip()
assert key and secret and '\n' not in secret, 'credential fields must be non-empty and whitespace-clean'
import boto3
boto3.client('s3', aws_access_key_id=key, aws_secret_access_key=secret).list_buckets() # cheap auth probe Try / catch
from common.data_source.exceptions import CredentialExpiredError
try:
connector.validate_connector_settings()
except CredentialExpiredError as e:
if 'invalid or expired' in str(e):
prompt_reenter_credentials() # non-retryable until user acts
raise Prevention
- Strip secrets when reading from files/env/secret managers — trailing newlines cause SignatureDoesNotMatch
- Automate key rotation awareness: store the key id alongside the secret and alert when get_caller_identity stops recognizing it
When it happens
Trigger: list_objects_v2 probe returning SignatureDoesNotMatch (wrong secret for the key id, or a copy/paste with trailing whitespace), or InvalidAccessKeyId not accompanied by 403/AccessDenied (deleted or rotated access key). Also hit when an OCI/GCS S3-compatible secret key was regenerated but the old one is still configured.
Common situations: Access key rotated by an admin and the connector config still holds the old pair; whitespace or newline contamination when pasting secrets; using an S3-compatible provider's console key after deleting it; environment drift between environments (prod secret copied to staging with a different key id).
Related errors
- main() must be defined or exported.
- Bitbucket
- main() returned a non-JSON-serializable value.
- message.compileNotSupported
- Failed to delete memory
AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15).
Data as JSON: /api/errors/53b923a4312c57d6.
Report an issue: GitHub.