{"record":{"id":"9828825820b0904a","repo":"risingwavelabs/risingwave","slug":"failed-to-create-google-cloud-pub-sub-token-source","errorCode":null,"errorMessage":"Failed to create Google Cloud Pub/Sub token source provider","messagePattern":"Failed to create Google Cloud Pub/Sub token source provider","errorType":"error_code","errorClass":"SinkError::GooglePubSub","httpStatus":null,"severity":"error","filePath":"src/connector/src/sink/google_pubsub.rs","lineNumber":231,"sourceCode":"        format_desc: &SinkFormatDesc,\n        db_name: String,\n        sink_from_name: String,\n    ) -> Result<Self> {\n        let environment = if let Some(ref cred) = config.credentials {\n            let mut auth_config = project::Config::default();\n            auth_config = auth_config.with_audience(apiv1::conn_pool::AUDIENCE);\n            auth_config = auth_config.with_scopes(&apiv1::conn_pool::SCOPES);\n            let cred_file = CredentialsFile::new_from_str(cred).await.map_err(|e| {\n                SinkError::GooglePubSub(\n                    anyhow!(e).context(\"Failed to create Google Cloud Pub/Sub credentials file\"),\n                )\n            })?;\n            let provider =\n                DefaultTokenSourceProvider::new_with_credentials(auth_config, Box::new(cred_file))\n                    .await\n                    .map_err(|e| {\n                        SinkError::GooglePubSub(\n                            anyhow!(e).context(\n                                \"Failed to create Google Cloud Pub/Sub token source provider\",\n                            ),\n                        )\n                    })?;\n            Environment::GoogleCloud(Box::new(provider))\n        } else if let Some(emu_host) = config.emulator_host {\n            Environment::Emulator(emu_host)\n        } else {\n            return Err(SinkError::GooglePubSub(anyhow!(\n                \"Missing emulator_host or credentials in Google Pub/Sub sink\"\n            )));\n        };\n\n        let client_config = ClientConfig {\n            endpoint: config.endpoint,\n            project_id: Some(config.project_id),\n            environment,\n            ..Default::default()","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/connector/src/sink/google_pubsub.rs#L213-L249","documentation":"After loading the credentials file, the sink builds a DefaultTokenSourceProvider used to mint OAuth tokens for the Pub/Sub API. If token source construction fails (e.g. invalid key material, unusable service account), the error is wrapped with the context 'Failed to create Google Cloud Pub/Sub token source provider'.","triggerScenarios":"Credentials JSON parses but the service account is invalid: revoked key, malformed private_key, wrong auth audience/scopes, or GCP-side rejection while initializing the token source.","commonSituations":"Rotated/deleted service-account keys still referenced in config; private_key with unescaped newlines; disabled service accounts in the GCP project.","solutions":["Check the chained inner error for the root OAuth/key failure","Re-create the service-account key and update the `pubsub.credentials` value with fresh JSON","Verify the service account is enabled and has Pub/Sub Publisher permission; use the emulator to isolate auth issues"],"exampleFix":"// before\npubsub.credentials='<old revoked key json>'\n// after\n# create a new key in GCP Console -> IAM -> Service Accounts -> Keys, then:\npubsub.credentials='<fresh key json>'","handlingStrategy":"try-catch","validationCode":"// Pre-check: key must parse and service account should be active (do this in a dry-run with google-auth)\nfn precheck_key_fields(cred: &str) -> Result<(), String> {\n    let v: serde_json::Value = serde_json::from_str(cred).map_err(|e| e.to_string())?;\n    if v[\"private_key\"].as_str().map_or(true, |k| !k.contains(\"BEGIN PRIVATE KEY\")) {\n        return Err(\"private_key missing PEM markers (check newline escaping)\".into());\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"match sink.new().await {\n    Err(e) if e.to_string().contains(\"token source provider\") => {\n        // inspect chained source; refresh service-account key\n        eprintln!(\"token source init failed: {e:#}\");\n    }\n    other => other?,\n}","preventionTips":["Rotate keys before expiry and update configs promptly","Ensure private_key newlines are \\\\n-escaped inside JSON","Grant the service account roles/pubsub.publisher"],"tags":["pubsub","gcp","oauth"],"backgroundTag":"oauth-token-exchange-failed","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}