{"record":{"id":"57af2147e76dab7a","repo":"neondatabase/neon","slug":"shard-connection-info-missing-for-shard","errorCode":null,"errorMessage":"shard connection info missing for shard {}","messagePattern":"shard connection info missing for shard (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libs/compute_api/src/spec.rs","lineNumber":332,"sourceCode":"                    shards,\n                    prefer_protocol: PageserverProtocol::Libpq,\n                })\n            }\n        }\n    }\n\n    /// Convenience routine to get the connection string for a shard.\n    pub fn shard_url(\n        &self,\n        shard_number: ShardNumber,\n        protocol: PageserverProtocol,\n    ) -> anyhow::Result<&str> {\n        let shard_index = ShardIndex {\n            shard_number,\n            shard_count: self.shard_count,\n        };\n        let shard = self.shards.get(&shard_index).ok_or_else(|| {\n            anyhow::anyhow!(\"shard connection info missing for shard {}\", shard_index)\n        })?;\n\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","sourceCodeStart":314,"sourceCodeEnd":350,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/libs/compute_api/src/spec.rs#L314-L350","documentation":"shard_url looks up the shard's connection info in the shards HashMap keyed by ShardIndex (shard_number + shard_count). If no entry exists for that exact index — typically because the requested shard number is out of range for the configured shard_count — the lookup fails and this error reports the missing index.","triggerScenarios":"Calling shard_url(shard_number, protocol) with a shard number >= shard_count, a shard number from a different (re)sharded generation, or an index built with a different shard_count than the one the map was populated with (from_connstr numbers shards 0..n-1).","commonSituations":"Iterating shard numbers from stale configuration after the tenant was split into more shards; mixing ShardIndex values from two different specs; off-by-one loops over shard numbers; requesting a shard after resharding changed the count.","solutions":["Iterate shard numbers in 0..shard_count (from PageserverConnectionInfo.shard_count) instead of a hardcoded or stale bound","Re-fetch/rebuild the connection info so its shard_count matches the current topology before resolving shard URLs","Validate the requested shard number against shard_count before calling shard_url and surface a clearer error"],"exampleFix":"// before\nfor shard in 0..8 {\n    let url = conn_info.shard_url(ShardNumber(shard), protocol)?;\n}\n// after\nfor shard in 0..conn_info.shard_count.0 {\n    let url = conn_info.shard_url(ShardNumber(shard), protocol)?;\n}","handlingStrategy":"type-guard","validationCode":"let idx = ShardIndex { shard_number, shard_count: conn_info.shard_count };\nif !conn_info.shards.contains_key(&idx) {\n    anyhow::bail!(\"shard {idx} missing (have {:?}); refresh connection info\",\n        conn_info.shards.keys().collect::<Vec<_>>());\n}","typeGuard":"fn has_shard(info: &PageserverConnectionInfo, shard_number: ShardNumber) -> bool {\n    let idx = ShardIndex { shard_number, shard_count: info.shard_count };\n    info.shards.contains_key(&idx)\n}","tryCatchPattern":null,"preventionTips":["Derive loop bounds from conn_info.shard_count, never from external constants","After any resharding, rebuild PageserverConnectionInfo before resolving shard URLs","Validate on load that shards covers exactly 0..shard_count"],"tags":["compute-api","sharding","lookup","rust"],"backgroundTag":"shard-not-found","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}