neondatabase/neon · error
no grpc_url for shard {shard_index}
Error message
no grpc_url for shard {shard_index} What it means
Thrown by PageserverConnectionInfo::shard_url() in neon's compute_api crate when the caller asks for the Grpc protocol but the first PageserverShardConnectionInfo entry for that shard has grpc_url: None. Both libpq_url and grpc_url are Option<String> on the shard connection info, which is deserialized from control-plane JSON, so a pageserver that only registered a libpq URL will fail this lookup. It is an anyhow error (not a typed error), surfaced as a plain Err(String) to the compute startup code.
Source
Thrown at libs/compute_api/src/spec.rs:348
};
let shard = self.shards.get(&shard_index).ok_or_else(|| {
anyhow::anyhow!("shard connection info missing for shard {}", shard_index)
})?;
// Just use the first pageserver in the list. That's good enough for this
// convenience routine; if you need more control, like round robin policy or
// failover support, roll your own. (As of this writing, we never have more than
// one pageserver per shard anyway, but that will change in the future.)
let pageserver = shard
.pageservers
.first()
.ok_or(anyhow::anyhow!("must have at least one pageserver"))?;
let result = match protocol {
PageserverProtocol::Grpc => pageserver
.grpc_url
.as_ref()
.ok_or(anyhow::anyhow!("no grpc_url for shard {shard_index}"))?,
PageserverProtocol::Libpq => pageserver
.libpq_url
.as_ref()
.ok_or(anyhow::anyhow!("no libpq_url for shard {shard_index}"))?,
};
Ok(result)
}
}
#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct PageserverShardInfo {
pub pageservers: Vec<PageserverShardConnectionInfo>,
}
#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct PageserverShardConnectionInfo {
pub id: Option<NodeId>,
pub libpq_url: Option<String>,View on GitHub (pinned to 8f60b04da4)
Solutions
- Check the shard's PageserverShardConnectionInfo and confirm grpc_url is populated; if the pageserver has no gRPC listener, call shard_url with PageserverProtocol::Libpq instead
- If you control the control-plane JSON, add the grpc:// URL for each pageserver so the field deserializes as Some(...)
- Fall back: try Grpc, and on this error retry the lookup with Libpq before giving up
- If you need per-pageserver selection or failover, iterate shard.pageservers yourself instead of using this first()-only convenience routine
Example fix
// before
let url = conn_info.shard_url(shard_number, PageserverProtocol::Grpc)?;
// after
let url = conn_info
.shard_url(shard_number, PageserverProtocol::Grpc)
.or_else(|_| conn_info.shard_url(shard_number, PageserverProtocol::Libpq))?; Defensive patterns
Strategy: validation
Validate before calling
// Before calling shard_url with Grpc, confirm the field exists:
fn has_grpc_url(ci: &PageserverConnectionInfo, sn: ShardNumber) -> bool {
let idx = ShardIndex { shard_number: sn, shard_count: ci.shard_count };
ci.shards
.get(&idx)
.and_then(|s| s.pageservers.first())
.and_then(|p| p.grpc_url.as_ref())
.is_some()
} Try / catch
// In Rust, treat it as a recoverable protocol-availability error:
match conn_info.shard_url(sn, PageserverProtocol::Grpc) {
Ok(url) => { /* use grpc */ }
Err(e) if e.to_string().contains("no grpc_url") => {
let url = conn_info.shard_url(sn, PageserverProtocol::Libpq)?;
}
Err(e) => return Err(e),
} Prevention
- Validate that grpc_url is populated for every shard before setting prefer_protocol to Grpc
- In control-plane/test code, assert both libpq_url and grpc_url are Some when building PageserverShardConnectionInfo
- Prefer checking prefer_protocol and available URLs together instead of hardcoding the protocol at call sites
When it happens
Trigger: Calling shard_url(shard_number, PageserverProtocol::Grpc) on a PageserverConnectionInfo whose shard map entry contains pageservers whose grpc_url field is null/absent. Happens when the control plane (e.g. neon_local / control_plane_builtin) only fills libpq_url for pageservers, but the compute was configured to prefer or explicitly use the gRPC protocol.
Common situations: Running a new compute against an older pageserver that does not expose a gRPC endpoint; mixed-version dev environments where the storage nodes never advertise grpc:// URLs; tests that hand-build PageserverShardConnectionInfo with only one of the two URL fields; toggling prefer_protocol to Grpc before the pageserver deployment actually publishes grpc_url.
Related errors
- no libpq_url for shard {shard_index}
- invalid connstring URL: {err}
- invalid protocol scheme: {scheme}
- invalid shard URL {url}: must use gRPC
- empty connection string
AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16).
Data as JSON: /api/errors/291fae215fca95a3.
Report an issue: GitHub.