linera-io/linera-protocol · error · async_graphql::Error
count exceeds u32
Error message
count exceeds u32
What it means
The GraphQL schema generated for `ReentrantCustomCollectionView` exposes a derived `count` field typed u32. The entry count is a `usize` from `iterative_count`; when it exceeds `u32::MAX` the narrowing conversion fails with 'count exceeds u32'. Only collections beyond ~4.29 billion entries can trigger it — it is a schema-limit guard.
Source
Thrown at linera-views/src/views/reentrant_collection_view.rs:2353
#[async_graphql::Object(cache_control(no_cache), name_type)]
impl<K, V> ReentrantCollectionView<V::Context, K, V>
where
K: async_graphql::InputType
+ async_graphql::OutputType
+ serde::ser::Serialize
+ serde::de::DeserializeOwned
+ std::fmt::Debug,
V: View + async_graphql::OutputType,
{
async fn keys(&self) -> Result<Vec<K>, async_graphql::Error> {
Ok(self.indices().await?)
}
#[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: K,
) -> Result<Entry<K, ReadGuardedView<V>>, async_graphql::Error> {
let value = self
.try_load_entry(&key)
.await?
.ok_or_else(|| missing_key_error(&key))?;
Ok(Entry { value, key })
}
async fn entries(
&self,
input: Option<MapInput<K>>,
) -> Result<Vec<Entry<K, ReadGuardedView<V>>>, async_graphql::Error> {
let keys = if let Some(keys) = inputView on GitHub (pinned to 6c226ddcb3)
Solutions
- Page via `keys`/`entries` and aggregate client-side instead of calling `count` on giant views.
- Bound growth by pruning or sharding entries across multiple views.
- Maintain an explicit u64 counter in application state.
- Request an upstream change widening the GraphQL field if >2^32 entries is a real requirement.
Example fix
# before
query { app { state { records { count } } } } # 'count exceeds u32'
# after
query { app { state { records { keys(count: 1000) } } } } # paginate; expose recordsTotal as u64 in the app Defensive patterns
Strategy: fallback
Validate before calling
# page a single key first
query { app { state { records { keys(count: 1) } } } } Try / catch
try { return await gql.query('query { app { state { records { count } } } }'); } catch (e) { if (/count exceeds u32/i.test(e.message)) { return tallyViaPagedKeys('records'); } throw e; } Prevention
- Prune nested-view collections aggressively; each entry is itself a view.
- Expose an explicit counter in application state.
- Page with keys/entries rather than counting.
When it happens
Trigger: Querying `count` on a ReentrantCustomCollectionView (views containing other views as values) holding more than 4,294,967,295 entries.
Common situations: Long-lived applications storing one nested view per operation with no pruning; adversarial/stress tests deliberately exceeding the u32 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/bfa16d58bcc848c7.
Report an issue: GitHub.