{"record":{"id":"fb6b2d23cd66fda2","repo":"neondatabase/neon","slug":"could-not-get-total-sessions","errorCode":null,"errorMessage":"could not get total_sessions: {}","messagePattern":"could not get total_sessions: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compute_tools/src/monitor.rs","lineNumber":434,"sourceCode":"                'template1'\n            );\",\n        &[],\n    );\n    let stats = match stats {\n        Ok(stats) => stats,\n        Err(e) => {\n            return Err(anyhow::anyhow!(\"could not query active_time: {}\", e));\n        }\n    };\n\n    let active_time: f64 = match stats.try_get(\"total_active_time\") {\n        Ok(active_time) => active_time,\n        Err(e) => return Err(anyhow::anyhow!(\"could not get total_active_time: {}\", e)),\n    };\n\n    let sessions: i64 = match stats.try_get(\"total_sessions\") {\n        Ok(sessions) => sessions,\n        Err(e) => return Err(anyhow::anyhow!(\"could not get total_sessions: {}\", e)),\n    };\n\n    Ok((active_time, sessions))\n}\n\n// Figure out the most recent state change time across all client backends.\n// If there is currently active backend, timestamp will be `Utc::now()`.\n// It can return `None`, which means no client backends exist or we were\n// unable to parse the timestamp.\nfn get_backends_state_change(cli: &mut Client) -> anyhow::Result<Option<DateTime<Utc>>> {\n    let mut last_active: Option<DateTime<Utc>> = None;\n    // Get all running client backends except ourself, use RFC3339 DateTime format.\n    let backends = cli.query(\n        \"SELECT state, pg_catalog.to_char(state_change, 'YYYY-MM-DD\\\"T\\\"HH24:MI:SS.US\\\"Z\\\"'::pg_catalog.text) AS state_change\n                FROM pg_stat_activity\n                    WHERE backend_type OPERATOR(pg_catalog.=) 'client backend'::pg_catalog.text\n                    AND pid OPERATOR(pg_catalog.!=) pg_catalog.pg_backend_pid()\n                    AND usename OPERATOR(pg_catalog.!=) 'cloud_admin'::pg_catalog.name;\", // XXX: find a better way to filter other monitors?","sourceCodeStart":416,"sourceCodeEnd":452,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/compute_tools/src/monitor.rs#L416-L452","documentation":"The final column conversion in get_database_stats(): stats.try_get(\"total_sessions\") to i64 failed because the 'total_sessions' column is not the BIGINT/INT8 the Rust side expects. The query intentionally casts to ::pg_catalog.bigint, so this error signals query/type drift rather than a bad value. It propagates as a check() error (downtime + reconnect).","triggerScenarios":"Column 'total_sessions' not of SQL type INT8: cast removed in a query edit, alias renamed, or a server returning a different type for sum(sessions).","commonSituations":"Editing monitor SQL without updating conversions; Postgres version changes in type inference for sum() over pg_stat_database columns.","solutions":["Restore the explicit cast: coalesce(sum(sessions), 0)::pg_catalog.bigint AS total_sessions","Read the inner FromSql error for the concrete type mismatch","Confirm the 'total_sessions' alias still exists in the query","Add a regression test asserting the (f64, i64) tuple round-trips"],"exampleFix":"// before\n\"pg_catalog.coalesce(pg_catalog.sum(sessions), 0) AS total_sessions\"\n\n// after\n\"pg_catalog.coalesce(pg_catalog.sum(sessions), 0)::pg_catalog.bigint AS total_sessions\"","handlingStrategy":"validation","validationCode":"// keep the explicit cast so the column is always BIGINT on the wire\nconst GET_DB_STATS_SQL: &str = \"... pg_catalog.coalesce(pg_catalog.sum(sessions), 0)::pg_catalog.bigint AS total_sessions ...\";","typeGuard":"fn col_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":"let sessions: i64 = match stats.try_get(\"total_sessions\") {\n    Ok(v) => v,\n    Err(e) => {\n        warn!(\"total_sessions unreadable, skipping stats check: {e}\");\n        return Ok(());\n    }\n};","preventionTips":["Never remove the ::bigint cast when editing get_database_stats","Verify aliases survive query refactors","Add a unit/integration test for the stats tuple types"],"tags":["postgres","type-conversion","bigint","pg-stat-database","rust"],"backgroundTag":"postgres-column-type-mismatch","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}