{"record":{"id":"8f58e7ab782ca822","repo":"neondatabase/neon","slug":"n-shards-but-no-stripe-size","errorCode":null,"errorMessage":"{n} shards but no stripe_size","messagePattern":"(.+?) shards but no stripe_size","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libs/compute_api/src/spec.rs","lineNumber":293,"sourceCode":"        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                }\n                let shard_count = ShardCount(n.try_into()?);\n                let shards = shard_infos\n                    .into_iter()\n                    .enumerate()\n                    .map(|(idx, shard_info)| {\n                        (\n                            ShardIndex {\n                                shard_count,\n                                shard_number: ShardNumber(\n                                    idx.try_into().expect(\"shard number fits in u8\"),\n                                ),\n                            },\n                            shard_info,\n                        )\n                    })\n                    .collect();\n                Ok(PageserverConnectionInfo {","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/libs/compute_api/src/spec.rs#L275-L311","documentation":"PageserverConnectionInfo::from_connstr treats each comma-separated connection string as one shard. When more than one is present (n > 1), the system is sharded, and a ShardStripeSize must accompany the shard count to distribute keys across shards. Passing no stripe_size in the multi-shard case is a spec inconsistency and bails immediately.","triggerScenarios":"Calling from_connstr with a connstr containing commas (multiple shard connection strings) while stripe_size is None — e.g. a legacy sharded ComputeSpec or neon.pageserver_connstring GUC set to several URLs without the accompanying stripe-size configuration.","commonSituations":"Upgrading a sharded deployment that still uses the legacy pageserver_connstring field; copy-pasting multi-shard connstrs without the stripe size parameter; partial migration to pageserver_connection_info where stripe size was dropped.","solutions":["Supply the stripe_size argument (e.g. from the spec's stripe size field, default 32768) when parsing a multi-shard connstr","Migrate the spec to the pageserver_connection_info field, which carries stripe_size per spec","If the deployment is really unsharded, remove the comma / extra connection strings so exactly one remains"],"exampleFix":"// before\nlet info = PageserverConnectionInfo::from_connstr(connstr, None)?;\n// after\nlet stripe = spec.stripe_size.map(ShardStripeSize)\n    .unwrap_or(ShardStripeSize::new(32768).unwrap());\nlet info = PageserverConnectionInfo::from_connstr(connstr, Some(stripe))?","handlingStrategy":"validation","validationCode":"let n_shards = connstr.split(',').count();\nanyhow::ensure!(n_shards == 1 || stripe_size.is_some(),\n    \"{n_shards} shard connection strings require a stripe_size\");\nlet info = PageserverConnectionInfo::from_connstr(connstr, stripe_size)?;","typeGuard":"fn shard_config_is_consistent(connstr: &str, stripe_size: Option<ShardStripeSize>) -> bool {\n    let n = connstr.split(',').count();\n    n == 1 || stripe_size.is_some()\n}","tryCatchPattern":null,"preventionTips":["Treat shard count and stripe size as one atomic piece of configuration","When emitting legacy connstrs for sharded systems, always emit the matching stripe size"],"tags":["compute-api","sharding","stripe-size","spec-parsing","rust"],"backgroundTag":"missing-shard-configuration","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}