linera-io/linera-protocol · error · async_graphql::Error
count exceeds u32
Error message
count exceeds u32
What it means
The GraphQL schema generated for `MapView` exposes a derived `count` field typed u32. The true number of keys is a `usize` produced by `iterative_count`; if it exceeds `u32::MAX` the `u32::try_from` fails and the resolver returns 'count exceeds u32'. This can only happen with over four billion map entries — an overflow guard, rarely seen in practice.
Source
Thrown at linera-views/src/views/map_view.rs:2282
+ Clone
+ Send
+ Sync
+ 'static,
{
async fn keys(&self, count: Option<usize>) -> Result<Vec<I>, async_graphql::Error> {
let indices = self.indices().await?;
let it = indices.iter().cloned();
Ok(if let Some(count) = count {
it.take(count).collect()
} else {
it.collect()
})
}
#[graphql(derived(name = "count"))]
async fn count_(&self) -> Result<u32, async_graphql::Error> {
let count = self.iterative_count().await?;
u32::try_from(count).map_err(|_| async_graphql::Error::new("count exceeds u32"))
}
async fn entry(&self, key: I) -> Result<Entry<I, Option<V>>, async_graphql::Error> {
Ok(Entry {
value: self.get(&key).await?,
key,
})
}
async fn entries(
&self,
input: Option<MapInput<I>>,
) -> Result<Vec<Entry<I, Option<V>>>, async_graphql::Error> {
let keys = input
.and_then(|input| input.filters)
.and_then(|filters| filters.keys);
let keys = if let Some(keys) = keys {
keysView on GitHub (pinned to 6c226ddcb3)
Solutions
- Use `keys(count: n)` / `entries(input: { filters: { keys: [...] } })` for paginated or targeted access instead of `count`.
- Prune or archive old map entries so the collection stays representable.
- Expose an explicit u64 counter in the application state rather than the derived `count`.
- Upstream, widen the field type if >2^32 entries is genuinely needed.
Example fix
# before
query { app { state { balances { count } } } } # fails past u32::MAX keys
# after
query { app { state { balances { entry(key: "<account>") { value } } } } } # targeted lookup; track total separately Defensive patterns
Strategy: fallback
Validate before calling
# targeted entry lookup avoids the count entirely
query { app { state { balances { entry(key: "<account>") { value } } } } } Try / catch
try { return await gql.query('query { app { state { balances { count } } } }'); } catch (e) { if (/count exceeds u32/i.test(e.message)) { return tallyViaPagedKeys('balances'); } throw e; } Prevention
- Use entry(key) for point lookups instead of counting the whole map.
- Expire or aggregate historical map entries.
- Track totals in an explicit u64 field.
When it happens
Trigger: Querying `count` on a MapView that has accumulated more than 4,294,967,295 keys (e.g. per-account records in a very long-lived application).
Common situations: Unbounded per-operation map growth without pruning; synthetic tests filling a map past the boundary.
Related errors
- count exceeds u32
- count exceeds u32
- count exceeds u32
- Query {argument:?} is invalid and could not be deserialized
- Attempt to modify storage from a service
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/0d98bfccbf1f4faf.
Report an issue: GitHub.