{"record":{"id":"8192b32419060526","repo":"neondatabase/neon","slug":"no-libpq-url-for-shard-shard-index","errorCode":null,"errorMessage":"no libpq_url for shard {shard_index}","messagePattern":"no libpq_url for shard (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libs/compute_api/src/spec.rs","lineNumber":352,"sourceCode":"\n        // Just use the first pageserver in the list. That's good enough for this\n        // convenience routine; if you need more control, like round robin policy or\n        // failover support, roll your own. (As of this writing, we never have more than\n        // one pageserver per shard anyway, but that will change in the future.)\n        let pageserver = shard\n            .pageservers\n            .first()\n            .ok_or(anyhow::anyhow!(\"must have at least one pageserver\"))?;\n\n        let result = match protocol {\n            PageserverProtocol::Grpc => pageserver\n                .grpc_url\n                .as_ref()\n                .ok_or(anyhow::anyhow!(\"no grpc_url for shard {shard_index}\"))?,\n            PageserverProtocol::Libpq => pageserver\n                .libpq_url\n                .as_ref()\n                .ok_or(anyhow::anyhow!(\"no libpq_url for shard {shard_index}\"))?,\n        };\n        Ok(result)\n    }\n}\n\n#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]\npub struct PageserverShardInfo {\n    pub pageservers: Vec<PageserverShardConnectionInfo>,\n}\n\n#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]\npub struct PageserverShardConnectionInfo {\n    pub id: Option<NodeId>,\n    pub libpq_url: Option<String>,\n    pub grpc_url: Option<String>,\n}\n\n#[derive(Clone, Debug, Default, Deserialize, Serialize)]","sourceCodeStart":334,"sourceCodeEnd":370,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/libs/compute_api/src/spec.rs#L334-L370","documentation":"Thrown by PageserverConnectionInfo::shard_url() in neon's compute_api when the Libpq protocol is requested but the first pageserver entry for the shard has libpq_url: None. libpq_url is Option<String> on PageserverShardConnectionInfo, populated from control-plane data; this error means the shard map knows about the pageserver but has no postgres-protocol connection string for it. It is the libpq twin of the 'no grpc_url for shard' error.","triggerScenarios":"Calling shard_url(shard_number, PageserverProtocol::Libpq) when the shard's first pageservers entry lacks libpq_url (null in the JSON). Typical when the control plane only fills grpc_url, or a test constructs PageserverShardConnectionInfo { id, grpc_url: Some(...), libpq_url: None }.","commonSituations":"Newer deployments that moved pageservers to gRPC-only management; stale or partial control-plane state after an upgrade; unit tests building shard info by hand that forget the libpq field; asking for the default protocol on a shard that was never given a postgres connection string.","solutions":["Inspect the shard map and use PageserverProtocol::Grpc if grpc_url is the populated field","Fix the source of the connection info so libpq_url is emitted for every pageserver in the shard","Fall back: try Libpq, and on this error retry with Grpc","For multi-pageserver shards, pick a pageserver entry that actually has the URL you need instead of relying on first()"],"exampleFix":"// before\nlet url = conn_info.shard_url(shard_number, PageserverProtocol::Libpq)?;\n\n// after\nlet url = conn_info\n    .shard_url(shard_number, PageserverProtocol::Libpq)\n    .or_else(|_| conn_info.shard_url(shard_number, PageserverProtocol::Grpc))?;","handlingStrategy":"validation","validationCode":"// Before calling shard_url with Libpq, confirm the field exists:\nfn has_libpq_url(ci: &PageserverConnectionInfo, sn: ShardNumber) -> bool {\n    let idx = ShardIndex { shard_number: sn, shard_count: ci.shard_count };\n    ci.shards\n        .get(&idx)\n        .and_then(|s| s.pageservers.first())\n        .and_then(|p| p.libpq_url.as_ref())\n        .is_some()\n}","typeGuard":null,"tryCatchPattern":"// Degrade to the other protocol when the preferred URL is absent:\nlet url = conn_info\n    .shard_url(sn, PageserverProtocol::Libpq)\n    .or_else(|_| conn_info.shard_url(sn, PageserverProtocol::Grpc))?;","preventionTips":["Keep the control-plane shard JSON populated with both libpq_url and grpc_url whenever the pageserver offers both","Log which URL fields are missing when building PageserverConnectionInfo so skew is visible early","Do not assume the default protocol is always available; check the Option fields first"],"tags":["neon","pageserver","libpq","connection-string","compute-api"],"backgroundTag":"missing-endpoint-url","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}