neondatabase/neon · error

failed to parse autovacuum workers count: {}

Error message

failed to parse autovacuum workers count: {}

What it means

The autovacuum-count query (`select count(*) from pg_stat_activity where backend_type = 'autovacuum worker'`) succeeded, but r.try_get::<&str, i64>("count") failed - the 'count' column could not be converted to i64. Since count(*) is int8, this points at type/schema drift or a mangled row rather than a runtime value issue. The error aborts check() and is handled as downtime plus reconnect.

Source

Thrown at compute_tools/src/monitor.rs:335

                    "failed to get list of active logical replication subscriptions: {}",
                    e
                ));
            }
        }

        // Do not suspend compute if autovacuum is running
        const AUTOVACUUM_COUNT_QUERY: &str =
            "select count(*) from pg_stat_activity where backend_type = 'autovacuum worker'";
        match cli.query_one(AUTOVACUUM_COUNT_QUERY, &[]) {
            Ok(r) => match r.try_get::<&str, i64>("count") {
                Ok(num_workers) => {
                    if num_workers > 0 {
                        self.last_active = Some(Utc::now());
                        return Ok(());
                    };
                }
                Err(e) => {
                    return Err(anyhow::anyhow!(
                        "failed to parse autovacuum workers count: {}",
                        e
                    ));
                }
            },
            Err(e) => {
                return Err(anyhow::anyhow!(
                    "failed to get list of autovacuum workers: {}",
                    e
                ));
            }
        }

        Ok(())
    }
}

// Hang on condition variable waiting until the compute status is `Running`.

View on GitHub (pinned to 8f60b04da4)

Solutions

  1. Cast explicitly in SQL: `count(*)::pg_catalog.bigint`
  2. Read the inner FromSql error to see expected vs actual type
  3. Keep the query and the try_get type in sync when modifying monitor queries
  4. Cover monitor queries with integration tests against your shipped PG version

Example fix

// before
const AUTOVACUUM_COUNT_QUERY: &str =
    "select count(*) from pg_stat_activity where backend_type = 'autovacuum worker'";

// after
const AUTOVACUUM_COUNT_QUERY: &str =
    "select count(*)::pg_catalog.bigint from pg_stat_activity where backend_type = 'autovacuum worker'";
Defensive patterns

Strategy: validation

Validate before calling

// pin the wire type in SQL so try_get::<_, i64> cannot mismatch
const AUTOVACUUM_COUNT_QUERY: &str =
    "select count(*)::pg_catalog.bigint from pg_stat_activity where backend_type = 'autovacuum worker'";

Type guard

fn count_is_int8(row: &postgres::Row, col: &str) -> bool {
    row.columns()
        .iter()
        .any(|c| c.name() == col && *c.type_() == postgres::types::Type::INT8)
}

Try / catch

match r.try_get::<&str, i64>("count") {
    Ok(n) => { /* use n */ }
    Err(e) => warn!("autovacuum count unreadable, skipping: {e}"), // non-fatal for the check
}

Prevention

When it happens

Trigger: try_get mismatch: 'count' column not of SQL type INT8, column absent, or a Postgres version/build whose count output type differs.

Common situations: Postgres major-version upgrades or patched builds changing system-view expression types; query edits that drop the 'count' alias without updating the Rust side.

Understand the failure class

Related errors


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