{"record":{"id":"32db97953dd2f54c","repo":"neondatabase/neon","slug":"could-not-get-total-active-time","errorCode":null,"errorMessage":"could not get total_active_time: {}","messagePattern":"could not get total_active_time: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compute_tools/src/monitor.rs","lineNumber":429,"sourceCode":"            pg_catalog.coalesce(pg_catalog.sum(sessions), 0)::pg_catalog.bigint AS total_sessions\n        FROM pg_catalog.pg_stat_database\n        WHERE datname NOT IN (\n                'postgres',\n                'template0',\n                '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(","sourceCodeStart":411,"sourceCodeEnd":447,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/compute_tools/src/monitor.rs#L411-L447","documentation":"After get_database_stats()' query succeeded, stats.try_get(\"total_active_time\") to f64 failed - the 'total_active_time' column could not be converted to f64. The query explicitly casts to ::pg_catalog.float8 precisely to match Rust's f64, so seeing this error implies the query text or expected types drifted (someone removed the cast, the column was renamed, or a non-float8 type arrived). It surfaces as a monitor check() failure.","triggerScenarios":"The selected column is not SQL type FLOAT8: the ::float8 cast was dropped in a query edit, the alias changed, or an exotic server returns a different type for sum(active_time).","commonSituations":"Refactoring the monitor query without keeping conversions aligned; running against Postgres versions or forks where sum()/coalesce() type inference differs.","solutions":["Restore the explicit cast: coalesce(sum(active_time), 0.0)::pg_catalog.float8 AS total_active_time","Check the inner FromSql error for expected vs actual type","Verify the column alias 'total_active_time' is still produced","Keep explicit pg_catalog casts on all monitor statistics columns (the codebase convention)"],"exampleFix":"// before\n\"pg_catalog.coalesce(pg_catalog.sum(active_time), 0.0) AS total_active_time\"\n\n// after\n\"pg_catalog.coalesce(pg_catalog.sum(active_time), 0.0)::pg_catalog.float8 AS total_active_time\"","handlingStrategy":"validation","validationCode":"// keep the explicit cast so the column is always FLOAT8 on the wire\nconst GET_DB_STATS_SQL: &str = \"SELECT pg_catalog.coalesce(pg_catalog.sum(active_time), 0.0)::pg_catalog.float8 AS total_active_time ...\";","typeGuard":"fn col_is_float8(row: &postgres::Row, col: &str) -> bool {\n    row.columns()\n        .iter()\n        .any(|c| c.name() == col && *c.type_() == postgres::types::Type::FLOAT8)\n}","tryCatchPattern":"let active_time: f64 = match stats.try_get(\"total_active_time\") {\n    Ok(v) => v,\n    Err(e) => {\n        warn!(\"total_active_time unreadable, skipping stats check: {e}\");\n        return Ok(()); // don't fail the whole monitor tick\n    }\n};","preventionTips":["Never remove the ::float8 cast when editing get_database_stats","Keep column aliases and Rust conversions in sync in one commit","Regression-test the (f64, i64) tuple against a real Postgres"],"tags":["postgres","type-conversion","float8","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"}