{"record":{"id":"5ee193bfd669cfea","repo":"risingwavelabs/risingwave","slug":"credentials-must-be-set-if-not-using-the-pubsub-em","errorCode":null,"errorMessage":"credentials must be set if not using the pubsub emulator","messagePattern":"credentials must be set if not using the pubsub emulator","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/connector/src/source/google_pubsub/enumerator/client.rs","lineNumber":50,"sourceCode":"impl SplitEnumerator for PubsubSplitEnumerator {\n    type Properties = PubsubProperties;\n    type Split = PubsubSplit;\n\n    async fn new(\n        properties: Self::Properties,\n        _context: SourceEnumeratorContextRef,\n    ) -> ConnectorResult<PubsubSplitEnumerator> {\n        if properties.parallelism.is_some() {\n            tracing::warn!(\n                \"pubsub.parallelism is deprecated and will be ignored. \\\n                 Split count now adapts automatically to the number of actors.\"\n            );\n        }\n\n        properties.subscriber_config()?;\n\n        if properties.credentials.is_none() && properties.emulator_host.is_none() {\n            bail!(\"credentials must be set if not using the pubsub emulator\")\n        }\n\n        let sub = properties.subscription_client().await?;\n        if !sub\n            .exists(None)\n            .await\n            .context(\"error checking subscription validity\")?\n        {\n            bail!(\"subscription {} does not exist\", &sub.id())\n        }\n\n        let seek_to = match (properties.start_offset, properties.start_snapshot) {\n            (None, None) => None,\n            (Some(start_offset), None) => {\n                let ts = start_offset\n                    .parse::<i64>()\n                    .context(\"error parsing start_offset\")\n                    .map(|nanos| Utc.timestamp_nanos(nanos).into())?;","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/connector/src/source/google_pubsub/enumerator/client.rs#L32-L68","documentation":"The Google PubSub source enumerator client requires credentials to authenticate to the PubSub service. If neither `credentials` nor `emulator_host` is provided in the source properties, client construction bails with this error, because google-cloud-pubsub cannot build an authenticated client without them.","triggerScenarios":"Creating a PubSub source with neither `credentials` (service-account JSON) nor `pubsub.emulator_host` set in the WITH clause, then calling PubsubEnumeratorClient::new.","commonSituations":"Local testing against the real service without supplying the service account key; deploying to an environment where ADC (Application Default Credentials) isn't set up and RisingWave requires explicit credentials; forgetting the credentials field after copying a config that used an emulator.","solutions":["Add the service-account credentials JSON to the WITH clause: `credentials = '...json content or path...'` for the source.","For local development, set `pubsub.emulator_host = 'host:port'` in the WITH clause to skip real authentication.","Alternatively point to a credentials file path or set GOOGLE_APPLICATION_CREDENTIALS if the properties support ADC-based lookup.","Verify the credentials JSON is a valid service-account key (has private_key, client_email) since invalid JSON will fail later."],"exampleFix":"-- before\nCREATE SOURCE ps (...) WITH (\n  connector = 'google_pubsub',\n  pubsub.subscription = 'my-sub'\n)\n-- after\nCREATE SOURCE ps (...) WITH (\n  connector = 'google_pubsub',\n  pubsub.subscription = 'my-sub',\n  pubsub.credentials = '{\"type\": \"service_account\", ...}'\n)","handlingStrategy":"validation","validationCode":"-- pre-check: exactly one of credentials/emulator_host present\nSELECT\n  (properties::jsonb ? 'pubsub.credentials') OR (properties::jsonb ? 'pubsub.emulator_host') AS auth_ok\nFROM (SELECT '{...}' AS properties) t;","typeGuard":"function hasPubsubAuth(props) {\n  return Boolean(props.credentials) || Boolean(props.emulator_host);\n}","tryCatchPattern":"match PubsubEnumeratorClient::new(props).await {\n    Ok(c) => c,\n    Err(e) if e.to_string().contains(\"credentials must be set\") => {\n        bail!(\"provide pubsub.credentials or pubsub.emulator_host: {e}\")\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Always supply either credentials JSON or emulator_host when defining PubSub sources.","Store the service-account key in a secret manager and inject it at deploy time.","Validate source properties with a dry-run before creating the source in production."],"tags":["gcp","pubsub","authentication","configuration"],"backgroundTag":"missing-credentials","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"}