{"record":{"id":"6afbe6ae92eabdae","repo":"neondatabase/neon","slug":"empty-connection-string","errorCode":null,"errorMessage":"empty connection string","messagePattern":"empty connection string","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libs/compute_api/src/spec.rs","lineNumber":276,"sourceCode":"/// the 'pageserver_connection_info' field should be used instead.\nimpl PageserverConnectionInfo {\n    pub fn from_connstr(\n        connstr: &str,\n        stripe_size: Option<ShardStripeSize>,\n    ) -> Result<PageserverConnectionInfo, anyhow::Error> {\n        let shard_infos: Vec<_> = connstr\n            .split(',')\n            .map(|connstr| PageserverShardInfo {\n                pageservers: vec![PageserverShardConnectionInfo {\n                    id: None,\n                    libpq_url: Some(connstr.to_string()),\n                    grpc_url: None,\n                }],\n            })\n            .collect();\n\n        match shard_infos.len() {\n            0 => anyhow::bail!(\"empty connection string\"),\n            1 => {\n                // We assume that if there's only connection string, it means \"unsharded\",\n                // rather than a sharded system with just a single shard. The latter is\n                // possible in principle, but we never do it.\n                let shard_count = ShardCount::unsharded();\n                let only_shard = shard_infos.first().unwrap().clone();\n                let shards = vec![(ShardIndex::unsharded(), only_shard)];\n                Ok(PageserverConnectionInfo {\n                    shard_count,\n                    stripe_size: None,\n                    shards: shards.into_iter().collect(),\n                    prefer_protocol: PageserverProtocol::Libpq,\n                })\n            }\n            n => {\n                if stripe_size.is_none() {\n                    anyhow::bail!(\"{n} shards but no stripe_size\");\n                }","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/libs/compute_api/src/spec.rs#L258-L294","documentation":"PageserverConnectionInfo::from_connstr parses a legacy comma-separated list of libpq connection strings (ComputeSpec::pageserver_connstring or the neon.pageserver_connstring GUC) into shard info. Each comma-separated element becomes one shard, so the count is always at least one for any input including the empty string; the 0-shard arm is a defensive guard that effectively fires only if the split yields no elements at all.","triggerScenarios":"Calling from_connstr in a way that yields zero shard entries — practically only reachable via inputs that short-circuit the split (the arm exists to future-proof the match). Real-world near-misses are empty-string connstrs, which instead produce a single empty-URL shard and fail later at connection time.","commonSituations":"Migrating legacy specs that still use pageserver_connstring instead of the modern pageserver_connection_info field; passing an unset env var or empty GUC value through this legacy path.","solutions":["Prefer the modern pageserver_connection_info field in ComputeSpec instead of the legacy connstr string","Validate that the connstr is non-empty and contains a real libpq URL before calling from_connstr","If you maintain a caller of from_connstr, treat zero parsed shards as invalid input and report which field was empty"],"exampleFix":"// before\nlet info = PageserverConnectionInfo::from_connstr(&spec.pageserver_connstring.unwrap_or_default(), stripe_size)?;\n// after\nlet connstr = spec.pageserver_connstring.as_deref().filter(|s| !s.trim().is_empty())\n    .ok_or_else(|| anyhow::anyhow!(\"pageserver_connstring missing\"))?;\nlet info = PageserverConnectionInfo::from_connstr(connstr, stripe_size)?;","handlingStrategy":"validation","validationCode":"let trimmed = connstr.trim();\nanyhow::ensure!(!trimmed.is_empty(), \"connection string is empty\");\nanyhow::ensure!(trimmed.starts_with(\"postgresql://\") || trimmed.starts_with(\"postgres://\"),\n    \"connection string does not look like a libpq URL: {trimmed}\");\nlet info = PageserverConnectionInfo::from_connstr(trimmed, stripe_size)?;","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate connstrs are non-empty libpq URLs before parsing","Migrate specs to pageserver_connection_info so structure is validated by serde, not string splitting"],"tags":["compute-api","connection-string","spec-parsing","rust"],"backgroundTag":"invalid-connection-string","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}