FuelLabs/fuel-core · error · anyhow::Error

No P2P service available

Error message

No P2P service available

What it means

P2PAdapter holds Option<Service>; when the node runs without P2P (feature off or networking not configured) the adapter is built with service: None and every PeerToPeerPort method that needs the network errors. This one is get_sealed_block_headers: header fetches from peers are impossible. Note height_stream degrades to a pending stream, so the failure only appears once sync actually fetches.

Source

Thrown at crates/fuel-core/src/service/adapters/sync.rs:56

            Some(service) => fuel_core_services::stream::IntoBoxStream::into_boxed(
                tokio_stream::wrappers::BroadcastStream::new(
                    service.subscribe_block_height(),
                )
                .filter_map(|r| futures::future::ready(r.ok().map(|r| r.block_height))),
            ),
            _ => fuel_core_services::stream::IntoBoxStream::into_boxed(
                tokio_stream::pending(),
            ),
        }
    }

    async fn get_sealed_block_headers(
        &self,
        block_height_range: Range<u32>,
    ) -> anyhow::Result<SourcePeer<Option<Vec<SealedBlockHeader>>>> {
        let result = match &self.service {
            Some(service) => service.get_sealed_block_headers(block_height_range).await,
            _ => Err(anyhow::anyhow!("No P2P service available")),
        };
        match result {
            Ok((peer_id, headers)) => {
                let peer_id: PeerId = peer_id.into();
                let headers = peer_id.bind(headers);
                Ok(headers)
            }
            Err(err) => Err(err),
        }
    }

    async fn get_transactions(
        &self,
        block_ids: Range<u32>,
    ) -> anyhow::Result<SourcePeer<Option<Vec<Transactions>>>> {
        let result = match &self.service {
            Some(service) => service.get_transactions(block_ids).await,
            _ => Err(anyhow::anyhow!("No P2P service available")),

View on GitHub (pinned to b9d4d170da)

Solutions

  1. Enable P2P: build with `--features p2p` and provide network configuration (bootstrap nodes, etc.).
  2. If networking is intentionally off, use snapshot/import-based sync instead of peer sync.
  3. Fix configs that both disable p2p and enable peer-driven sync.
Defensive patterns

Strategy: type-guard

Validate before calling

// Before relying on peer sync, confirm P2P is configured:
fn p2p_available(config: &Config) -> bool {
    #[cfg(feature = "p2p")]
    { config.p2p.is_some() }
    #[cfg(not(feature = "p2p"))]
    { false }
}
if !p2p_available(&config) {
    anyhow::bail!("peer header fetch unavailable: P2P not configured");
}

Type guard

fn is_peer_sync_capable(config: &Config) -> bool {
    cfg!(feature = "p2p") && config.p2p.is_some()
}

Try / catch

match header_fetch {
    Err(e) if e.to_string().contains("No P2P service available") => {
        // expected on non-networked nodes: fall back to snapshot/import sync
        tracing::warn!("P2P unavailable; skipping peer header fetch");
        return Ok(None);
    }
    other => other,
}

Prevention

When it happens

Trigger: The sync service calls get_sealed_block_headers(block_height_range) on a node whose P2PAdapter has no service — p2p disabled in config or the binary built without the p2p feature.

Common situations: Local/dev nodes started without network config but attempting state sync; binaries without the p2p feature pointed at a chain that requires peer sync; config where p2p is None while sync is active.

Related errors


AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16). Data as JSON: /api/errors/058edd64b1250cb4. Report an issue: GitHub.