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
- Pass at least one URL, e.g. FuelClient::with_urls(&["http://localhost:4000"]).
- Guard configuration loading with an explicit check and a clear message naming the missing setting.
- 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
- Validate URL lists at config load with a message naming the env var or setting.
- Default to a known endpoint (e.g. http://localhost:4000) in dev instead of an empty vec.
- For single endpoints prefer FuelClient::from, which normalizes scheme and host.
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
- Compression level {value} outside of allowed range 0..=22
- {error}
- on-chain database doesn't have height
- off-chain database doesn't have height
- Database doesn't have a height to rollback
AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16).
Data as JSON: /api/errors/48ef905fa14ab973.
Report an issue: GitHub.