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

  1. Give each verifier a distinct set of failure-domain IDs so no ID appears in both identities.
  2. Remove the shared domain ID from the provider where it does not apply.
  3. Re-tag your providers with domains reflecting real independence (different region/ASN/vendor).
  4. 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

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/0c0930d564d41bf9. Report an issue: GitHub.