{"record":{"id":"247486d780bb5214","repo":"pola-rs/polars","slug":"expiration-time-in-sts-response-did-not-contain-ti","errorCode":null,"errorMessage":"expiration time in STS response did not contain timezone information","messagePattern":"expiration time in STS response did not contain timezone information","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/io/cloud/credential_provider/_providers.py","lineNumber":239,"sourceCode":"            if isinstance(expiry := getattr(creds, \"_expiry_time\", None), datetime)\n            else None\n        )\n\n        return creds_dict, expiry\n\n    def _finish_assume_role(self, session: Any) -> CredentialProviderFunctionReturn:\n        assert self.assume_role is not None\n\n        client = session.client(\"sts\")\n\n        sts_response = client.assume_role(**self.assume_role)\n        creds = sts_response[\"Credentials\"]\n\n        expiry = creds[\"Expiration\"]\n\n        if expiry.tzinfo is None:\n            msg = \"expiration time in STS response did not contain timezone information\"\n            raise ValueError(msg)\n\n        return {\n            \"aws_access_key_id\": creds[\"AccessKeyId\"],\n            \"aws_secret_access_key\": creds[\"SecretAccessKey\"],\n            \"aws_session_token\": creds[\"SessionToken\"],\n        }, int(expiry.timestamp())\n\n    # Called from Rust, mainly for AWS endpoint_url\n    def _storage_update_options(self) -> dict[str, str]:\n        if self._storage_options_has_endpoint_url:\n            return {}\n\n        try:\n            config = self._session()._session.get_scoped_config()\n        except ImportError:\n            return {}\n\n        if endpoint_url := config.get(\"endpoint_url\"):","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/io/cloud/credential_provider/_providers.py#L221-L257","documentation":"CredentialProviderAWS._finish_assume_role (py-polars/src/polars/io/cloud/credential_provider/_providers.py:226-247) calls boto3 STS assume_role and reads response['Credentials']['Expiration'], converting it to a UNIX timestamp via expiry.timestamp(). A naive datetime (tzinfo None) would make that conversion timezone-ambiguous, so polars raises ValueError rather than guessing. Real AWS STS always returns tz-aware datetimes, so this almost always indicates a non-standard STS endpoint.","triggerScenarios":"scanning/writing s3:// with credential_provider=pl.CredentialProviderAWS(assume_role={...}) where the STS endpoint is a mock (moto, stubbed boto3) or a proxy returning an Expiration without a timezone offset.","commonSituations":"Unit/integration tests that stub boto3 Session.client('sts').assume_role with datetime.now() (naive); custom corporate STS proxies that strip offsets; patched boto3 responses in test fixtures.","solutions":["Fix the mock/endpoint to return tz-aware datetimes: datetime.now(timezone.utc) - matching real AWS behavior","If a corporate proxy is stripping timezone info, report/fix it upstream","In test fixtures, build the full Credentials dict including a tz-aware Expiration"],"exampleFix":"# before (test stub returning a naive datetime)\nsts.assume_role.return_value = {\"Credentials\": {\"Expiration\": datetime.now(), ...}}\n# after\nfrom datetime import timezone\nsts.assume_role.return_value = {\"Credentials\": {\"Expiration\": datetime.now(timezone.utc), ...}}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    df = pl.scan_parquet(path, credential_provider=provider).collect()\nexcept ValueError as e:\n    if \"timezone information\" in str(e):\n        raise RuntimeError(\n            \"STS endpoint returned a naive Expiration; fix the STS mock/proxy\"\n        ) from e\n    raise","preventionTips":["In tests, always build STS Expiration with datetime.now(timezone.utc)","Treat naive Expiration datetimes from corporate STS proxies as an upstream bug to report","Run assume_role paths against real or faithful STS emulators in integration tests"],"tags":["polars","aws","sts","assume-role","boto3","testing"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}