{"record":{"id":"98c5a395c6bd1d5d","repo":"FuelLabs/fuel-core","slug":"total-balance-overflow-coins-coins-messages","errorCode":null,"errorMessage":"Total balance overflow: coins: {coins}, messages: {non_retryable}","messagePattern":"Total balance overflow: coins: (.+?), messages: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/fuel-core/src/service/adapters/graphql_api/off_chain.rs","lineNumber":225,"sourceCode":"        base_asset_id: &AssetId,\n    ) -> StorageResult<TotalBalanceAmount> {\n        let coins = self\n            .storage_as_ref::<CoinBalances>()\n            .get(&CoinBalancesKey::new(owner, asset_id))?\n            .unwrap_or_default()\n            .into_owned() as TotalBalanceAmount;\n\n        if base_asset_id == asset_id {\n            let MessageBalance {\n                retryable: _, // TODO: https://github.com/FuelLabs/fuel-core/issues/2448\n                non_retryable,\n            } = self\n                .storage_as_ref::<MessageBalances>()\n                .get(owner)?\n                .unwrap_or_default()\n                .into_owned();\n\n            let total = coins.checked_add(non_retryable).ok_or(anyhow::anyhow!(\n                \"Total balance overflow: coins: {coins}, messages: {non_retryable}\"\n            ))?;\n            Ok(total)\n        } else {\n            Ok(coins)\n        }\n    }\n\n    fn balances<'a>(\n        &'a self,\n        owner: &Address,\n        start: Option<AssetId>,\n        base_asset_id: &'a AssetId,\n        direction: IterDirection,\n    ) -> BoxedIter<'a, StorageResult<(AssetId, TotalBalanceAmount)>> {\n        match (direction, start) {\n            (IterDirection::Forward, None) => {\n                self.base_asset_first(owner, base_asset_id, direction)","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/FuelLabs/fuel-core/blob/b9d4d170da3a31c9ace5f963d633b326348e0d42/crates/fuel-core/src/service/adapters/graphql_api/off_chain.rs#L207-L243","documentation":"The GraphQL off-chain balance query adds the owner's base-asset coin total and non-retryable message balance with checked_add on TotalBalanceAmount (u64). Overflow requires the combined value to exceed u64::MAX — a state a sane chain cannot reach — so this is a sanity guard against corrupted storage or absurd genesis amounts, not an expected arithmetic event.","triggerScenarios":"Querying balance(owner, base_asset_id) when stored coin total + non_retryable message balance > u64::MAX — corrupted balances table, hand-crafted genesis with near-max amounts, or test fixtures summing saturated values.","commonSituations":"Chains created from custom snapshots with miscomputed supply; storage corruption after hardware faults; integration tests that max out balances.","solutions":["Inspect the owner's coins and MessageBalances records for max-value/corrupted entries and repair the state.","When building test chains, keep minted amounts well below u64::MAX.","If this fires on a healthy chain, treat it as storage corruption and report upstream with the owner's state."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// At the GraphQL/API boundary, surface the guard as a clean query error:\nmatch balance_result {\n    Ok(total) => Some(total),\n    Err(e) if e.to_string().contains(\"Total balance overflow\") => {\n        tracing::error!(\"corrupt balance state for owner {owner:?}\");\n        None // or a domain-specific GraphQL error\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Validate snapshot amounts at chain-creation time (sums below u64::MAX).","Treat this error as data corruption — investigate the owner's coins/messages, don't retry.","In test chains, avoid near-u64::MAX mint values."],"tags":["graphql","balance","overflow","storage","sanity-guard"],"backgroundTag":null,"analyzedSha":"b9d4d170da3a31c9ace5f963d633b326348e0d42","analyzedAt":"2026-08-16T08:56:42.692Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}