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

  1. Re-verify the credential pair for correctness (key id exists, secret matches) even though the message is generic — read the embedded error_code
  2. If the provider is S3-compatible, test the same credentials with its own CLI (mc, rclone) to isolate status-code quirks
  3. Check system clock sync (NTP) — signing uses the timestamp, and skew can produce signature errors with unusual statuses
  4. 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

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


AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15). Data as JSON: /api/errors/20c1952cc7ed750c. Report an issue: GitHub.