FuelLabs/fuel-core · error · anyhow::Error
Failed to read stream entries from Redis node: {e}
Error message
Failed to read stream entries from Redis node: {e} What it means
Same batch-read path (crates/fuel-core/src/service/adapters/consensus_module/poa.rs:715) but Redis answered with an error ({e}) rather than timing out. The node's cached connection is reset and its whole read counts as failed; if the remaining successful reads drop below quorum, the caller aborts with the 'Cannot reconcile' error.
Source
Thrown at crates/fuel-core/src/service/adapters/consensus_module/poa.rs:715
let count = u32::try_from(max_entries).unwrap_or(u32::MAX);
let stream_entries = timeout(
self.node_timeout,
redis::Script::new(READ_STREAM_ENTRIES_SCRIPT)
.key(&self.block_stream_key)
.arg(next_height)
.arg(count)
.invoke_async::<Vec<(u32, u64, Vec<u8>, String)>>(&mut connection),
)
.await;
let entries = match stream_entries {
Err(_) => {
self.clear_cached_connection(redis_node).await;
return Err(anyhow!("Timed out reading stream entries from Redis node"));
}
Ok(Err(e)) => {
self.clear_cached_connection(redis_node).await;
return Err(anyhow!(
"Failed to read stream entries from Redis node: {e}"
));
}
Ok(Ok(entries)) => entries,
};
let mut blocks = Vec::new();
for (height, epoch, bytes, _stream_id) in entries {
match postcard::from_bytes::<SealedBlock>(&bytes) {
Ok(block) => blocks.push((height, epoch, block)),
Err(e) => {
tracing::warn!(
"Skipping stream entry: failed to deserialize block at height {height}: {e}"
);
}
}
}
View on GitHub (pinned to b9d4d170da)
Solutions
- Act on the {e} payload: free Redis memory (maxmemory) or disk, fix ACL/credentials
- Ensure {lease_key}:block:stream is actually a stream (WRONGTYPE → remove the foreign key)
- Return the node to a healthy primary state; quorum of remaining nodes keeps the chain alive meanwhile
Defensive patterns
Strategy: retry
Validate before calling
// pre-flight server health per node: // redis-cli INFO persistence -> rdb_last_bgsave_status:ok // redis-cli CONFIG GET maxmemory / maxmemory-policy -> reads must not be rejected // redis-cli TYPE <lease_key>:block:stream -> stream
Try / catch
match read_entries(node, h, n).await {
Err(e) if e.to_string().contains("Failed to read stream entries") => {
// parse {e}: WRONGTYPE/MISCONF/OOM/NOAUTH each map to a specific op action;
}
other => other,
} Prevention
- Set maxmemory with headroom and an eviction policy that never rejects stream reads
- Monitor disk space on Redis hosts (MISCONF prevention)
- Keep ACLs stable; coordinate credential rotation with node restarts
When it happens
Trigger: Redis errors during the XRANGE-style batch read: WRONGTYPE on block_stream_key, MISCONF persistence failure, NOAUTH/ACL denial, OOM command rejection under maxmemory, or read-only replica errors.
Common situations: Redis maxmemory reached so reads are rejected; disk-full MISCONF state; permission/ACL changes; the stream key overwritten by non-stream data.
Related errors
- Failed to read latest stream entry from Redis node: {e}
- Timed out reading latest stream entry from Redis node
- Invalid latest stream entry height: {e}
- Timed out reading stream entries from Redis node
- Backlog unresolved at height {current_height}: stream indica
AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16).
Data as JSON: /api/errors/64b010a9878aa983.
Report an issue: GitHub.