neondatabase/neon · error

empty connection string

Error message

empty connection string

What it means

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.

Source

Thrown at libs/compute_api/src/spec.rs:276

/// the 'pageserver_connection_info' field should be used instead.
impl PageserverConnectionInfo {
    pub fn from_connstr(
        connstr: &str,
        stripe_size: Option<ShardStripeSize>,
    ) -> Result<PageserverConnectionInfo, anyhow::Error> {
        let shard_infos: Vec<_> = connstr
            .split(',')
            .map(|connstr| PageserverShardInfo {
                pageservers: vec![PageserverShardConnectionInfo {
                    id: None,
                    libpq_url: Some(connstr.to_string()),
                    grpc_url: None,
                }],
            })
            .collect();

        match shard_infos.len() {
            0 => anyhow::bail!("empty connection string"),
            1 => {
                // We assume that if there's only connection string, it means "unsharded",
                // rather than a sharded system with just a single shard. The latter is
                // possible in principle, but we never do it.
                let shard_count = ShardCount::unsharded();
                let only_shard = shard_infos.first().unwrap().clone();
                let shards = vec![(ShardIndex::unsharded(), only_shard)];
                Ok(PageserverConnectionInfo {
                    shard_count,
                    stripe_size: None,
                    shards: shards.into_iter().collect(),
                    prefer_protocol: PageserverProtocol::Libpq,
                })
            }
            n => {
                if stripe_size.is_none() {
                    anyhow::bail!("{n} shards but no stripe_size");
                }

View on GitHub (pinned to 8f60b04da4)

Solutions

  1. Prefer the modern pageserver_connection_info field in ComputeSpec instead of the legacy connstr string
  2. Validate that the connstr is non-empty and contains a real libpq URL before calling from_connstr
  3. If you maintain a caller of from_connstr, treat zero parsed shards as invalid input and report which field was empty

Example fix

// before
let info = PageserverConnectionInfo::from_connstr(&spec.pageserver_connstring.unwrap_or_default(), stripe_size)?;
// after
let connstr = spec.pageserver_connstring.as_deref().filter(|s| !s.trim().is_empty())
    .ok_or_else(|| anyhow::anyhow!("pageserver_connstring missing"))?;
let info = PageserverConnectionInfo::from_connstr(connstr, stripe_size)?;
Defensive patterns

Strategy: validation

Validate before calling

let trimmed = connstr.trim();
anyhow::ensure!(!trimmed.is_empty(), "connection string is empty");
anyhow::ensure!(trimmed.starts_with("postgresql://") || trimmed.starts_with("postgres://"),
    "connection string does not look like a libpq URL: {trimmed}");
let info = PageserverConnectionInfo::from_connstr(trimmed, stripe_size)?;

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16). Data as JSON: /api/errors/6afbe6ae92eabdae. Report an issue: GitHub.