{"record":{"id":"512c9f9369de01af","repo":"dbt-labs/dbt-core","slug":"failed-to-parse-vortex-endpoint-url","errorCode":null,"errorMessage":"Failed to parse Vortex endpoint URL","messagePattern":"Failed to parse Vortex endpoint URL","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/vortex-client/src/client.rs","lineNumber":424,"sourceCode":"    sender: mpsc::Sender<(Box<VortexMessage>, bool)>,\n    thread_handle: WorkerThread,\n    /// Path to the file where messages will be written in dev mode.\n    ///\n    /// Only set in development mode. MUST be `None` in production.\n    dev_mode_output_path: Option<PathBuf>,\n    /// Dev-mode output writer, used to write messages to a file in development mode.\n    dev_mode_output_writer: Mutex<Result<fs::File, io::Error>>,\n}\n\nimpl VortexProducerClient {\n    pub fn from_env(env: &dyn VortexEnv) -> Self {\n        let endpoint = {\n            let base_url = env.base_url();\n            let ingest_endpoint = env.ingest_endpoint();\n            let full_url = format!(\"{base_url}{ingest_endpoint}\");\n            full_url\n                .parse::<http::Uri>()\n                .expect(\"Failed to parse Vortex endpoint URL\")\n        };\n        let vortex_client_platform = {\n            // Construct the X-Vortex-Client-Platform header with service, client, and proto library\n            // information. Format:\n            //\n            //     {service}/{version} {client}/{version} {proto_library}/{version}\n            //\n            // This helps identify the client platform and its components for monitoring and debugging.\n            let service_name = env.service_name();\n            let service_version = env.service_version();\n            // TODO: Change this to the actual version of the proto-rust library.\n            let proto_version = \"unknown\";\n            #[allow(clippy::uninlined_format_args)]\n            let header_value_string = format!(\n                \"{}/{} {}/{} {}/{}\",\n                service_name,\n                service_version,\n                \"vortex-client-rust\",","sourceCodeStart":406,"sourceCodeEnd":442,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/vortex-client/src/client.rs#L406-L442","documentation":"Panic from `.expect()` in `VortexClient::from_env` when `format!(\"{base_url}{ingest_endpoint}\")` fails to parse as an `http::Uri`. Environment-provided endpoint configuration is treated as mandatory-correct: a malformed URL aborts startup instead of returning a Result.","triggerScenarios":"Setting the Vortex base-URL / ingest-endpoint environment variables to values that are not valid `http::Uri`s — e.g. missing scheme (`my.host.com/path` instead of `https://my.host.com/path`), spaces, invalid characters, a double slash producing `http://a//b`, or an empty base_url yielding an unparseable concatenation.","commonSituations":"Config from profiles/CI with a hostname but no scheme; trailing/leading whitespace in the env var; typos like `http:/host`; self-hosted endpoints with custom ports written incorrectly (`host:port` without scheme).","solutions":["Fix the endpoint environment variables so the full URL includes a valid scheme and host, e.g. `https://vortex.example.com/ingest`.","Validate with a quick check before launching: `python3 -c \"from urllib.parse import urlparse; urlparse('YOUR_URL')\"` or paste into `http::Uri::try_from` mentally — scheme://host[/path].","Trim whitespace and remove stray characters from the env values (quotes pasted from docs are a common culprit).","Prefer changing the code path to propagate a config error via `Result` instead of `.expect` if you maintain a fork, so misconfiguration fails with a clear message."],"exampleFix":"// before (env)\nVORTEX_BASE_URL=myhost.example.com/ingest\n\n// after (env)\nVORTEX_BASE_URL=https://myhost.example.com\nVORTEX_INGEST_ENDPOINT=/ingest","handlingStrategy":"validation","validationCode":"// validate endpoint env values before starting the client\nlet base = std::env::var(\"VORTEX_BASE_URL\")?;\nassert!(base.starts_with(\"http://\") || base.starts_with(\"https://\"), \"VORTEX_BASE_URL must include scheme\");\nassert!(!base.trim().is_empty() && base.trim() == base, \"VORTEX_BASE_URL must not be empty or contain whitespace\");","typeGuard":"fn is_valid_uri(s: &str) -> bool {\n    s.parse::<http::Uri>().is_ok()\n        && matches!(s.parse::<http::Uri>().unwrap().scheme_str(), Some(\"http\" | \"https\"))\n}","tryCatchPattern":"// in a fork, replace expect with Result so misconfig fails cleanly\nlet uri: http::Uri = full_url.parse().map_err(|e|\n    VortexError::Config(format!(\"invalid VORTEX endpoint URL '{full_url}': {e}\")))?;","preventionTips":["Always include the scheme (`https://`) in base-url env values.","Trim whitespace and avoid pasting surrounding quotes from documentation.","Validate endpoint URLs in CI/config loading with the same `http::Uri` parser.","Keep base_url and ingest_endpoint values consistent (no duplicated or missing slashes) and test the concatenation."],"tags":["http","url","configuration","env","panic"],"backgroundTag":"invalid-url-format","analyzedSha":"0267ce9170576975b76b64ce856b2e5848e96617","analyzedAt":"2026-09-07T21:53:39.732Z","contentChangedAt":"2026-09-07T21:53:39.732Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}