{"record":{"id":"d5c78f0eb0cdb49c","repo":"neondatabase/neon","slug":"invalid-connstring-url-err","errorCode":null,"errorMessage":"invalid connstring URL: {err}","messagePattern":"invalid connstring URL: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libs/compute_api/src/spec.rs","lineNumber":648,"sourceCode":"#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]\npub enum PageserverProtocol {\n    /// The original protocol based on libpq and COPY. Uses postgresql:// or postgres:// scheme.\n    #[default]\n    #[serde(rename = \"libpq\")]\n    Libpq,\n    /// A newer, gRPC-based protocol. Uses grpc:// scheme.\n    #[serde(rename = \"grpc\")]\n    Grpc,\n}\n\nimpl PageserverProtocol {\n    /// Parses the protocol from a connstring scheme. Defaults to Libpq if no scheme is given.\n    /// Errors if the connstring is an invalid URL.\n    pub fn from_connstring(connstring: &str) -> anyhow::Result<Self> {\n        let scheme = match Url::parse(connstring) {\n            Ok(url) => url.scheme().to_lowercase(),\n            Err(url::ParseError::RelativeUrlWithoutBase) => return Ok(Self::default()),\n            Err(err) => return Err(anyhow!(\"invalid connstring URL: {err}\")),\n        };\n        match scheme.as_str() {\n            \"postgresql\" | \"postgres\" => Ok(Self::Libpq),\n            \"grpc\" => Ok(Self::Grpc),\n            scheme => Err(anyhow!(\"invalid protocol scheme: {scheme}\")),\n        }\n    }\n\n    /// Returns the URL scheme for the protocol, for use in connstrings.\n    pub fn scheme(&self) -> &'static str {\n        match self {\n            Self::Libpq => \"postgresql\",\n            Self::Grpc => \"grpc\",\n        }\n    }\n}\n\nimpl Display for PageserverProtocol {","sourceCodeStart":630,"sourceCodeEnd":666,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/libs/compute_api/src/spec.rs#L630-L666","documentation":"Thrown by PageserverProtocol::from_connstring() in neon's compute_api when the `url` crate fails to parse the connstring with any error other than RelativeUrlWithoutBase (which is treated as a scheme-less connstring and defaults to Libpq). Typical underlying url::ParseError values are EmptyHost and invalid characters/ports, so this fires on strings that look like a URL (contain a scheme separator) but are malformed as URLs.","triggerScenarios":"Calling from_connstring(\"postgres://\") or from_connstring(\"grpc://:50051\") (EmptyHost), or a connstring with illegal characters in the host/port such as \"postgresql://host:notaport/db\". Any scheme-bearing string that Url::parse rejects triggers it.","commonSituations":"Config or environment variable holding a half-filled connstring, e.g. postgres:// with the host templated out; connstrings assembled by string concatenation where a variable expanded to empty; copy-paste of a libpq keyword/value string (host=localhost port=5432) into a field that expects a URL; trailing spaces or control characters.","solutions":["Log/inspect the exact connstring and the embedded {err} from url::ParseError (EmptyHost is the most common) and fix the host part","If you meant a scheme-less connstring, remove the scheme separator entirely so parse hits RelativeUrlWithoutBase and defaults to Libpq","Validate connstrings at config load time with Url::parse before they reach from_connstring","Check for empty variables used to build the URL (empty host, empty port)"],"exampleFix":"# before\nPAGESERVER_CONNSTRING=\"postgres://\"          # EmptyHost -> error\nPAGESERVER_CONNSTRING=\"grpc://:50051\"       # EmptyHost -> error\n\n# after\nPAGESERVER_CONNSTRING=\"postgres://pageserver-0.neon:6400\"\nPAGESERVER_CONNSTRING=\"grpc://pageserver-0.neon:50051\"","handlingStrategy":"validation","validationCode":"// Validate connstrings at config load time:\nfn valid_connstring(s: &str) -> bool {\n    match url::Url::parse(s) {\n        Ok(_) => true,\n        Err(url::ParseError::RelativeUrlWithoutBase) => true, // scheme-less is OK\n        Err(_) => false,\n    }\n}","typeGuard":null,"tryCatchPattern":"// Log the underlying url::ParseError and the offending string at startup:\nif let Err(e) = PageserverProtocol::from_connstring(&cfg.ps_connstring) {\n    anyhow::bail!(\"bad PAGESERVER_CONNSTRING {:?}: {e}\", cfg.ps_connstring);\n}","preventionTips":["Never build connstrings by naive concatenation of possibly-empty variables","Validate connstrings when loading config, not at first use deep in startup","Prefer fully-qualified URLs (scheme + host) in configuration files"],"tags":["neon","pageserver","url-parsing","connection-string","compute-api"],"backgroundTag":"invalid-url","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}