{"record":{"id":"e68d1bc363476b10","repo":"risingwavelabs/risingwave","slug":"credentials-url-must-be-a-valid-url-s3-file","errorCode":null,"errorMessage":"credentials_url must be a valid URL (s3://, file://) or an absolute file path","messagePattern":"credentials_url must be a valid URL \\(s3://, file://\\) or an absolute file path","errorType":"validation","errorClass":"ConnectorError","httpStatus":null,"severity":"error","filePath":"src/connector/src/connector_common/common.rs","lineNumber":752,"sourceCode":"        Ok(res)\n    }\n\n    pub(crate) async fn resolve_pulsar_credentials_url(\n        &self,\n        oauth: &PulsarOauthCommon,\n        aws_auth_props: &AwsAuthProps,\n    ) -> ConnectorResult<(String, Option<NamedTempFile>)> {\n        // Try parsing as URL first\n        if let Ok(url) = Url::parse(&oauth.credentials_url) {\n            return self\n                .handle_pulsar_credentials_url(&url, aws_auth_props)\n                .await;\n        }\n\n        // If not a valid URL, check if it's an absolute file path\n        let path = Path::new(&oauth.credentials_url);\n        if !path.is_absolute() {\n            bail!(\"credentials_url must be a valid URL (s3://, file://) or an absolute file path\");\n        }\n\n        // Verify the file exists\n        if !tokio::fs::try_exists(&oauth.credentials_url)\n            .await\n            .unwrap_or(false)\n        {\n            bail!(\"credentials file does not exist: {}\", oauth.credentials_url);\n        }\n\n        // Return absolute path with file:// prefix\n        Ok((format!(\"file://{}\", oauth.credentials_url), None))\n    }\n\n    pub(crate) async fn handle_pulsar_credentials_url(\n        &self,\n        url: &Url,\n        aws_auth_props: &AwsAuthProps,","sourceCodeStart":734,"sourceCodeEnd":770,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/connector/src/connector_common/common.rs#L734-L770","documentation":"Raised by `resolve_pulsar_credentials_url` when a Pulsar OAuth2 `credentials_url` is neither a parseable URL with scheme file:// or s3://, nor an absolute filesystem path. The function tries URL parsing first, then falls back to `Path::is_absolute`; both failing means the value cannot be resolved to a credentials file.","triggerScenarios":"Setting `oauth.credentials_url` to a relative path like `creds.json`, an empty string, or a malformed URL (e.g. `s3:/bucket/file` missing a slash) while configuring a Pulsar source/sink with OAuth authentication.","commonSituations":"Using a relative path in config because it works locally but the process runs from a different working directory; typos in the URL scheme; copying credentials_url from another system with different path conventions.","solutions":["Use an absolute file path, e.g. `/etc/pulsar/creds.json`.","Use a valid `file:///path/to/creds.json` or `s3://bucket/creds.json` URL.","Fix scheme typos (e.g. `s3://` not `s3:/`) and ensure the value is non-empty."],"exampleFix":"// before\ncredentials_url = \"creds.json\"\n// after\ncredentials_url = \"/etc/risingwave/pulsar/creds.json\"","handlingStrategy":"validation","validationCode":"function validateCredentialsUrl(v) {\n  if (!v) throw new Error('credentials_url is empty');\n  if (v.startsWith('/')) return; // absolute path ok\n  try { const u = new URL(v); if (!['file:', 's3:'].includes(u.protocol)) throw new Error('bad scheme'); }\n  catch { throw new Error(`credentials_url must be file://, s3://, or an absolute path, got: ${v}`); }\n}\nvalidateCredentialsUrl(oauth.credentials_url);","typeGuard":"const isAbsolutePath = (v) => typeof v === 'string' && v.startsWith('/');","tryCatchPattern":"try { await createPulsarSource(cfg); } catch (e) { if (String(e).includes('credentials_url must be a valid URL')) throw new Error('Fix credentials_url: use file:///abs/path, s3://bucket/key, or an absolute path'); throw e; }","preventionTips":["Always use absolute paths or file:///s3:// URLs in credentials_url.","Never rely on relative paths; the server's working directory is not yours.","Add config linting that rejects credentials_url values without a known prefix."],"tags":["pulsar","oauth","url","config"],"backgroundTag":"invalid-url-format","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"}