nautechsystems/nautilus_trader · error
Provider failure domains must be pairwise disjoint
Error message
Provider failure domains must be pairwise disjoint
What it means
`validate_config` computes the failure-domain ID sets of every pair of verifier identities and requires them to be pairwise disjoint: no two providers may share a failure domain. This guarantees the two providers are in independent failure domains, which is the basis for trustworthy cross-verification. It throws when any domain ID appears in both providers' `failure_domain_ids`.
Source
Thrown at crates/adapters/blockchain/src/rpc/verification.rs:1195
identities
.iter()
.map(|identity| identity.provider_id.as_str()),
"provider IDs",
)?;
ensure_distinct(
identities
.iter()
.map(|identity| identity.operator_id.as_str()),
"operator IDs",
)?;
for left in 0..identities.len() {
for right in left + 1..identities.len() {
let left_domains = identities[left]
.failure_domain_ids
.iter()
.collect::<HashSet<_>>();
anyhow::ensure!(
identities[right]
.failure_domain_ids
.iter()
.all(|domain| !left_domains.contains(domain)),
"Provider failure domains must be pairwise disjoint"
);
}
}
let endpoints = [
normalize_endpoint(authoritative_url)?,
normalize_endpoint(config.verifiers[0].http_rpc_url.expose_secret())?,
normalize_endpoint(config.verifiers[1].http_rpc_url.expose_secret())?,
];
ensure_distinct(endpoints.iter().map(String::as_str), "provider endpoints")?;
let anchor = &config.chain_anchor;
anyhow::ensure!(anchor.chain_id != 0, "Chain anchor ID must be nonzero");View on GitHub (pinned to 18893faf8b)
Solutions
- Give each verifier a distinct set of failure-domain IDs so no ID appears in both identities.
- Remove the shared domain ID from the provider where it does not apply.
- Re-tag your providers with domains reflecting real independence (different region/ASN/vendor).
- Compute the intersection of the two `failure_domain_ids` sets locally to find the offending ID before editing.
Example fix
// before verifier_a.identity.failure_domain_ids = ["us-east-1", "primary"] verifier_b.identity.failure_domain_ids = ["us-west-2", "primary"] // after verifier_a.identity.failure_domain_ids = ["us-east-1", "primary"] verifier_b.identity.failure_domain_ids = ["us-west-2", "backup"]
Defensive patterns
Strategy: validation
Validate before calling
use std::collections::HashSet;
fn check_disjoint_failure_domains(cfg: &BlockchainVerificationConfig) -> Result<(), String> {
let domains: Vec<HashSet<&str>> = cfg.verifiers.iter()
.map(|v| v.identity.failure_domain_ids.iter().collect())
.collect();
for i in 0..domains.len() {
for j in i + 1..domains.len() {
if domains[i].intersection(&domains[j]).next().is_some() {
return Err(format!("verifiers {i} and {j} share a failure domain"));
}
}
}
Ok(())
} Type guard
fn failure_domains_disjoint(a: &[String], b: &[String]) -> bool {
let sa: HashSet<_> = a.iter().collect();
b.iter().all(|d| !sa.contains(d))
} Try / catch
match validate_config(&cfg) {
Err(e) if e.to_string().contains("pairwise disjoint") => {
eprintln!("Providers overlap in failure domains: {e}; re-tag identities");
std::process::exit(1);
}
other => other,
} Prevention
- Derive failure-domain IDs from real infrastructure attributes (region, ASN, vendor) and never copy-paste provider blocks wholesale.
- Assert disjointness in a config unit test with the production config file as input.
- Keep domain ID naming conventions unique per provider in your infrastructure-as-code templates.
When it happens
Trigger: Any pair of configured verifiers whose `identity.failure_domain_ids` lists share at least one common domain ID, detected by the nested loop over identities.
Common situations: Copying one provider's config block and forgetting to change its failure-domain IDs; both providers hosted by the same cloud region/ASN labeled identically; an operator reusing a shared 'primary' domain tag for both providers.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- request_rate_per_second must be greater than zero
- order_request_rate_per_second must be greater than zero
- heartbeat_secs must be positive when set
- heartbeat_timeout_secs must cover at least two server heartb
- `router_addresses` must contain at least one router address
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/0c0930d564d41bf9.
Report an issue: GitHub.