FuelLabs/fuel-core · error

Failed to create FuelClient. No URL is provided.

Error message

Failed to create FuelClient. No URL is provided.

What it means

FuelClient::with_urls builds a FailoverTransport from the given URL slice and rejects an empty list immediately with 'Failed to create FuelClient. No URL is provided.' (crates/client/src/client.rs:459). This is a fail-fast guard before any network activity. Unlike single-URL constructors such as FuelClient::from, with_urls requires at least one endpoint to construct the failover chain.

Source

Thrown at crates/client/src/client.rs:459

        rpc_url: R,
    ) -> anyhow::Result<Self> {
        let urls: Vec<_> = graph_ql_urls
            .map(|str| normalize_url(str.as_ref()))
            .try_collect()?;
        let mut client = Self::with_urls(&urls)?;
        let mut raw_rpc_url = <R as AsRef<str>>::as_ref(&rpc_url).to_string();
        if !raw_rpc_url.starts_with("http") {
            raw_rpc_url = format!("http://{raw_rpc_url}");
        }
        let rpc_client = ProtoBlockAggregatorClient::connect(raw_rpc_url).await?;
        client.rpc_client = Some(rpc_client);
        client.aws_client = AWSClientManager::new();
        Ok(client)
    }

    pub fn with_urls(urls: &[impl AsRef<str>]) -> anyhow::Result<Self> {
        if urls.is_empty() {
            return Err(anyhow!("Failed to create FuelClient. No URL is provided."));
        }
        let urls = urls
            .iter()
            .map(|url| normalize_url(url.as_ref()))
            .collect::<Result<Vec<_>, _>>()?;
        Ok(Self {
            transport: FailoverTransport::new(urls)?,
            require_height: ConsistencyPolicy::Auto {
                height: Arc::new(Mutex::new(None)),
            },
            chain_state_info: Default::default(),
            #[cfg(feature = "rpc")]
            rpc_client: None,
            #[cfg(feature = "rpc")]
            aws_client: AWSClientManager::new(),
            #[cfg(feature = "rpc")]
            http_client: remote_block_object_http_client(),
        })

View on GitHub (pinned to b9d4d170da)

Solutions

  1. Pass at least one URL, e.g. FuelClient::with_urls(&["http://localhost:4000"]).
  2. Guard configuration loading with an explicit check and a clear message naming the missing setting.
  3. For a single endpoint, prefer FuelClient::from("localhost:4000"), which also normalizes the scheme.

Example fix

// before
let urls: Vec<String> = std::env::var("NODE_URLS")?.split(',').map(str::to_string).collect();
let client = FuelClient::with_urls(&urls)?; // empty env → error

// after
let urls: Vec<String> = std::env::var("NODE_URLS")?
    .split(',')
    .map(str::trim)
    .filter(|s| !s.is_empty())
    .map(str::to_string)
    .collect();
anyhow::ensure!(!urls.is_empty(), "NODE_URLS must contain at least one Fuel node URL");
let client = FuelClient::with_urls(&urls)?;
Defensive patterns

Strategy: validation

Validate before calling

let urls: Vec<String> = raw.split(',').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string).collect();
anyhow::ensure!(!urls.is_empty(), "at least one Fuel node URL is required (check NODE_URLS)");
let client = FuelClient::with_urls(&urls)?;

Type guard

fn has_fuel_urls(urls: &[impl AsRef<str>]) -> bool {
    urls.iter().any(|u| !u.as_ref().trim().is_empty())
}

Prevention

When it happens

Trigger: FuelClient::with_urls(&urls) where urls is empty — typically a Vec built from an env var or comma-separated config string that produced zero entries.

Common situations: Empty or unset NODE_URL/FUEL_NODE_URL env var; config parsing that yields an empty list; defaulting logic returning vec![] instead of a default endpoint; test setup that forgets to inject the URL.

Related errors


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