neondatabase/neon · error

failed to get list of walsenders

Error message

failed to get list of walsenders: {}

What it means

check() runs `select count(*) from pg_stat_replication where application_name != 'walproposer'` to keep the compute from being suspended while (logical) walsenders are attached. This specific error fires when cli.query_one() itself fails; the column-conversion failure is a separate error ('failed to parse walsenders count'). On failure the monitor reports downtime and reconnects, same as other check() errors.

Solutions

  1. Read the nested error to distinguish connection loss from timeout
  2. Rely on the monitor's built-in reconnect: single failures are logged and retried every 500ms
  3. If persistent, verify Postgres health and pg_stat_replication is queryable as cloud_admin
  4. When using logical replication, expect walsender counts to keep computes awake - plan monitor logs accordingly
Defensive patterns

Strategy: retry

Try / catch

match cli.query_one(WS_COUNT_QUERY, &[]) {
    Ok(r) => { let n: i64 = r.get("count"); /* keep alive if n > 0 */ }
    Err(e) => { error!("failed to get list of walsenders: {e}"); client = conf.connect(NoTls); }
}

Prevention

When it happens

Trigger: query_one on pg_stat_replication returns Err: dropped connection, statement timeout, server restart, or the view being inaccessible during recovery transitions.

Common situations: Logical replication subscribers connected when the monitor connection breaks; computes with walproposer activity being polled during suspension handoff; transient errors during Postgres shutdown sequences.

Related errors


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

Appendix: source

Thrown at compute_tools/src/monitor.rs:291

        // N.B. walproposer doesn't currently show up in pg_stat_replication,
        // but protect if it will.
        const WS_COUNT_QUERY: &str =
            "select count(*) from pg_stat_replication where application_name != 'walproposer';";
        match cli.query_one(WS_COUNT_QUERY, &[]) {
            Ok(r) => match r.try_get::<&str, i64>("count") {
                Ok(num_ws) => {
                    if num_ws > 0 {
                        self.last_active = Some(Utc::now());
                        return Ok(());
                    }
                }
                Err(e) => {
                    let err: anyhow::Error = e.into();
                    return Err(err.context("failed to parse walsenders count"));
                }
            },
            Err(e) => {
                return Err(anyhow::anyhow!("failed to get list of walsenders: {}", e));
            }
        }

        // Don't suspend compute if there is an active logical replication subscription
        //
        // `where pid is not null` – to filter out read only computes and subscription on branches
        const LOGICAL_SUBSCRIPTIONS_QUERY: &str =
            "select count(*) from pg_stat_subscription where pid is not null;";
        match cli.query_one(LOGICAL_SUBSCRIPTIONS_QUERY, &[]) {
            Ok(row) => match row.try_get::<&str, i64>("count") {
                Ok(num_subscribers) => {
                    if num_subscribers > 0 {
                        self.last_active = Some(Utc::now());
                        return Ok(());
                    }
                }
                Err(e) => {
                    return Err(anyhow::anyhow!(

View on GitHub (pinned to 8f60b04da4)