{"record":{"id":"a981036eec84fc48","repo":"neondatabase/neon","slug":"failed-to-parse-pg-stat-subscription-count","errorCode":null,"errorMessage":"failed to parse 'pg_stat_subscription' count: {}","messagePattern":"failed to parse 'pg_stat_subscription' count: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compute_tools/src/monitor.rs","lineNumber":309,"sourceCode":"                return Err(anyhow::anyhow!(\"failed to get list of walsenders: {}\", e));\n            }\n        }\n\n        // Don't suspend compute if there is an active logical replication subscription\n        //\n        // `where pid is not null` – to filter out read only computes and subscription on branches\n        const LOGICAL_SUBSCRIPTIONS_QUERY: &str =\n            \"select count(*) from pg_stat_subscription where pid is not null;\";\n        match cli.query_one(LOGICAL_SUBSCRIPTIONS_QUERY, &[]) {\n            Ok(row) => match row.try_get::<&str, i64>(\"count\") {\n                Ok(num_subscribers) => {\n                    if num_subscribers > 0 {\n                        self.last_active = Some(Utc::now());\n                        return Ok(());\n                    }\n                }\n                Err(e) => {\n                    return Err(anyhow::anyhow!(\n                        \"failed to parse 'pg_stat_subscription' count: {}\",\n                        e\n                    ));\n                }\n            },\n            Err(e) => {\n                return Err(anyhow::anyhow!(\n                    \"failed to get list of active logical replication subscriptions: {}\",\n                    e\n                ));\n            }\n        }\n\n        // Do not suspend compute if autovacuum is running\n        const AUTOVACUUM_COUNT_QUERY: &str =\n            \"select count(*) from pg_stat_activity where backend_type = 'autovacuum worker'\";\n        match cli.query_one(AUTOVACUUM_COUNT_QUERY, &[]) {\n            Ok(r) => match r.try_get::<&str, i64>(\"count\") {","sourceCodeStart":291,"sourceCodeEnd":327,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/compute_tools/src/monitor.rs#L291-L327","documentation":"The subscription-count query succeeded, but row.try_get::<&str, i64>(\"count\") failed - the returned 'count' column could not be converted to i64. count(*) normally returns int8 which maps to i64, so this indicates schema/type drift (a different wire type or missing column) rather than a value problem. It propagates out of check() as a monitor error (downtime + reconnect).","triggerScenarios":"try_get type mismatch: the 'count' column's SQL type is not Type::INT8, the column is missing/renamed, or a PG version/extension changes the output type of the pg_stat_subscription count query.","commonSituations":"Running against an unusual Postgres build or a major-version upgrade that altered system-view output types; editing the monitor query without keeping the Rust conversion in sync.","solutions":["Add an explicit SQL cast so the wire type always matches: `count(*)::pg_catalog.bigint`","Check the inner FromSql error text - it names the expected versus actual type","Verify the exact query still selects a column aliased 'count' on your PG version","Compare with get_database_stats which already uses explicit ::float8/::bigint casts for this reason"],"exampleFix":"// before\nconst LOGICAL_SUBSCRIPTIONS_QUERY: &str =\n    \"select count(*) from pg_stat_subscription where pid is not null;\";\n\n// after\nconst LOGICAL_SUBSCRIPTIONS_QUERY: &str =\n    \"select count(*)::pg_catalog.bigint from pg_stat_subscription where pid is not null;\"","handlingStrategy":"validation","validationCode":"// pin the wire type in SQL so try_get::<_, i64> cannot mismatch\nconst LOGICAL_SUBSCRIPTIONS_QUERY: &str =\n    \"select count(*)::pg_catalog.bigint from pg_stat_subscription where pid is not null;\";","typeGuard":"fn count_is_int8(row: &postgres::Row, col: &str) -> bool {\n    row.columns()\n        .iter()\n        .any(|c| c.name() == col && *c.type_() == postgres::types::Type::INT8)\n}","tryCatchPattern":"match row.try_get::<&str, i64>(\"count\") {\n    Ok(n) => { /* use n */ }\n    Err(e) => warn!(\"skipping subscription count, unexpected type: {e}\"), // don't fail the whole check\n}","preventionTips":["Always cast count() to ::bigint in SQL when reading it as i64","Keep explicit pg_catalog casts on every monitor statistics column","Integration-test monitor queries against the shipped Postgres version"],"tags":["postgres","pg-stat-subscription","type-conversion","rust"],"backgroundTag":"postgres-column-type-mismatch","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}