{"record":{"id":"b5aa70beeeba9589","repo":"pola-rs/polars","slug":"unsupported-cannot-combine-token-with-unhandled","errorCode":null,"errorMessage":"unsupported: cannot combine token with {unhandled_key} in storage_options","messagePattern":"unsupported: cannot combine token with (.+?) in storage_options","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/io/cloud/credential_provider/_builder.py","lineNumber":526,"sourceCode":"                    k = k.lower()\n\n                    # https://docs.rs/object_store/latest/object_store/gcp/enum.GoogleConfigKey.html\n                    if k in {\"token\", \"bearer_token\"}:\n                        token = v\n                    elif k in AUTOINIT_IGNORED_KEYS:\n                        continue\n                    else:\n                        # We assume some sort of access key was given, so we\n                        # just dispatch to the rust side.\n                        unhandled_key = k\n\n            if unhandled_key is not None:\n                if token is not None:\n                    msg = (\n                        \"unsupported: cannot combine token with \"\n                        f\"{unhandled_key} in storage_options\"\n                    )\n                    raise ValueError(msg)\n\n                return None\n\n            if token is not None:\n                return CredentialProviderBuilder(\n                    InitializedCredentialProvider(UserProvidedGCPToken(token))\n                )\n\n            if (default := get_default_credential_provider()) is not None:\n                return default\n\n            return CredentialProviderBuilder(AutoInit(CredentialProviderGCP))\n\n        return None\n\n    credential_provider_init = f()\n\n    if verbose():","sourceCodeStart":508,"sourceCodeEnd":544,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/io/cloud/credential_provider/_builder.py#L508-L544","documentation":"In the GCP branch of the auto credential-provider builder (py-polars/src/polars/io/cloud/credential_provider/_builder.py:502-526), storage_options keys 'token'/'bearer_token' select a user-provided OAuth bearer token. Any other unrecognized key means raw credentials dispatched to the Rust side. Specifying a token together with any other credential key is contradictory and raises ValueError naming the conflicting key; an unrecognized key WITHOUT a token would simply fall through to native handling.","triggerScenarios":"pl.scan_parquet('gs://bucket/f.parquet', storage_options={'token': 'ya29....', 'service_account': '/secrets/sa.json'}) - token plus any non-ignored key raises, with the offending key name in the message.","commonSituations":"Short-lived access tokens injected by a scheduler combined with a base config carrying service-account settings; merging a shared GCS options dict with a per-run token.","solutions":["Remove either the token or the other credential key so exactly one auth source remains","For service-account/file-based auth, drop 'token' and let the native path handle the remaining keys","Regenerate the token per run instead of mixing it into a static config dict"],"exampleFix":"# before\nopts = {\"token\": TOKEN, \"service_account\": \"/secrets/sa.json\"}\nlf = pl.scan_parquet(\"gs://bucket/f.parquet\", storage_options=opts)\n# after\nlf = pl.scan_parquet(\"gs://bucket/f.parquet\", storage_options={\"service_account\": \"/secrets/sa.json\"})","handlingStrategy":"validation","validationCode":"def validate_gcs_storage_options(opts: dict) -> None:\n    has_token = any(k.lower() in {\"token\", \"bearer_token\"} for k in opts)\n    others = [k for k in opts if k.lower() not in {\"token\", \"bearer_token\"}]\n    if has_token and others:\n        raise ValueError(f\"cannot combine token with {others}; keep exactly one auth source\")","typeGuard":null,"tryCatchPattern":"try:\n    lf = pl.scan_parquet(path, storage_options=opts)\nexcept ValueError as e:\n    if \"cannot combine token\" in str(e):\n        opts = {k: v for k, v in opts.items() if k.lower() not in {\"token\", \"bearer_token\"}}\n        lf = pl.scan_parquet(path, storage_options=opts)\n    else:\n        raise","preventionTips":["Treat 'token' as an ephemeral override applied to a copy of the base options, not merged into the static dict","Build GCS options from a single source of truth (workload identity, SA key, or token)","Validate the merged dict before every scan call in job boilerplate"],"tags":["polars","gcp","gcs","credentials","storage-options","valueerror"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}