FuelLabs/fuel-core · error · anyhow::Error
At least one redis url is required for leader lock
Error message
At least one redis url is required for leader lock
What it means
RedisLeaderLeaseAdapter::new (crates/fuel-core/src/service/adapters/consensus_module/poa.rs:204) constructs the Redis-backed leader lock for multi-leader PoA. It first maps every URL through redis::Client::open (which itself fails on malformed URLs), then rejects an empty node list: quorum is nodes/2 + 1, so with zero nodes leadership could never be established.
Source
Thrown at crates/fuel-core/src/service/adapters/consensus_module/poa.rs:205
lease_key: String,
lease_ttl: Duration,
node_timeout: Duration,
retry_delay: Duration,
max_retry_delay_offset: Duration,
max_attempts: u32,
stream_max_len: u32,
) -> anyhow::Result<Self> {
let redis_nodes = redis_urls
.into_iter()
.map(|redis_url| {
redis::Client::open(redis_url).map(|redis_client| RedisNode {
redis_client,
cached_connection: Mutex::new(None),
})
})
.collect::<Result<Vec<_>, _>>()?;
if redis_nodes.is_empty() {
return Err(anyhow!(
"At least one redis url is required for leader lock"
));
}
let quorum_disruption_budget = 0u32;
let quorum = Self::calculate_quorum(redis_nodes.len(), quorum_disruption_budget);
let lease_ttl_millis = u64::try_from(lease_ttl.as_millis())?;
let retry_delay_millis = u64::try_from(retry_delay.as_millis())?;
let max_retry_delay_offset_millis =
u64::try_from(max_retry_delay_offset.as_millis())?;
let max_attempts = usize::try_from(max_attempts)?.max(1);
let lease_owner_token = uuid::Uuid::new_v4().to_string();
let epoch_key = format!("{lease_key}:epoch:token");
let block_stream_key = format!("{lease_key}:block:stream");
let lease_drift_millis = lease_ttl_millis
.checked_div(100)
.unwrap_or(0)
.saturating_add(2);
Ok(Self {View on GitHub (pinned to b9d4d170da)
Solutions
- Provide at least one valid Redis URL (redis://host:6379); for real fault tolerance use an odd count of 3 or more since quorum = majority
- If Redis leader locking is not wanted, configure the consensus without the Redis reconciliation adapter instead of passing an empty list
- Validate redis_urls non-empty during config parsing so the failure happens with a pointed config error before node start
Example fix
// before: RedisLeaderLeaseAdapter::new(vec![], key, ..)? // after: RedisLeaderLeaseAdapter::new( // vec!["redis://10.0.0.1:6379".into(), "redis://10.0.0.2:6379".into(), // "redis://10.0.0.3:6379".into()], // key, ..)?
Defensive patterns
Strategy: validation
Validate before calling
anyhow::ensure!(!redis_urls.is_empty(),
"consensus config: redis leader-lock requires at least one redis url");
anyhow::ensure!(redis_urls.len() % 2 == 1 && redis_urls.len() >= 3,
"recommended: odd number of redis urls >= 3 (quorum = majority)");
// run before RedisLeaderLeaseAdapter::new Try / catch
if let Err(e) = RedisLeaderLeaseAdapter::new(urls, ..) {
if e.to_string().contains("At least one redis url") {
// pure config error: fix config, never retry with same input
}
} Prevention
- Make redis_urls a required (non-default) field in the consensus config schema
- Fail config validation at load time with a clear message instead of at adapter construction
- Prefer 3+ odd-count deployments; a single URL is a single point of failure for leadership
When it happens
Trigger: Constructing the Redis leader-lock/reconciliation adapter with an empty redis_urls Vec — the config field omitted, defaulted to empty, or explicitly set to [].
Common situations: Chain config missing the redis leader-lock section; a YAML/JSON typo making the urls field parse as empty; attempting to disable locking by passing an empty list instead of using the non-Redis consensus setup (Noop adapter).
Related errors
- Timed out while connecting to redis leader-lock node
- epoch token lock poisoned: {}
- The override height is zero. The override height should be g
- Block not found at height: {:?}
- Timed out reading latest stream entry from Redis node
AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16).
Data as JSON: /api/errors/647659e7ce0b2d01.
Report an issue: GitHub.