FuelLabs/sway · error · anyhow::Error

Failed to fetch from {fetch_url:?}

Error message

Failed to fetch from {fetch_url:?}

What it means

Fallback fetch path used when the local API is not available: forc GETs {gateway}/ipfs/<cid>?download=true&filename=<cid>.tar.gz from a public (or configured) gateway and bails on any non-success status, printing the full URL.

Source

Thrown at forc-pkg/src/source/ipfs.rs:197

            .await
            .context("failed to read IPFS API response body")?;
        let tar = GzDecoder::new(bytes.as_ref());
        self.extract_archive(tar, dst)?;
        Ok(())
    }

    /// Using the provided gateway url, fetches the content described by this cid.
    pub(crate) async fn fetch_with_gateway_url(&self, gateway_url: &str, dst: &Path) -> Result<()> {
        let client = reqwest::Client::new();
        // We request the content to be served to us in tar format by the public gateway.
        let fetch_url = format!(
            "{}/ipfs/{}?download=true&filename={}.tar.gz",
            gateway_url, self.0, self.0
        );
        let req = client.get(&fetch_url);
        let res = req.send().await?;
        if !res.status().is_success() {
            anyhow::bail!("Failed to fetch from {fetch_url:?}");
        }
        let bytes: Vec<_> = res.bytes().await?.into_iter().collect();
        let tar = GzDecoder::new(bytes.as_slice());
        // After collecting and decoding bytes of the archive, we unpack it to the dst.
        self.extract_archive(tar, dst)?;
        Ok(())
    }
}

/// Returns the local IPFS HTTP API base URL, matching `IpfsClient::default()` behavior.
fn local_ipfs_api_base_url() -> String {
    read_ipfs_api_base_url_from_config().unwrap_or_else(|| DEFAULT_LOCAL_IPFS_API.to_string())
}

fn read_ipfs_api_base_url_from_config() -> Option<String> {
    let home = std::env::var_os("HOME").or_else(|| std::env::var_os("USERPROFILE"))?;
    let api_path = Path::new(&home).join(".ipfs").join("api");
    let contents = std::fs::read_to_string(api_path).ok()?;

View on GitHub (pinned to 47e5e902fa)

Solutions

  1. Retry after a short wait - public gateway failures are frequently transient
  2. Configure a different/custom gateway for the ipfs node setting in Forc.toml, or run a local node (which switches to the local API path)
  3. Verify the cid resolves by opening {gateway}/ipfs/<cid> in a browser
  4. Self-host a gateway or pin the content on a local node for reliability

Example fix

# before: single-shot build in CI that fails on transient gateway errors
forc build

# after: retry with backoff
for i in 1 2 3; do forc build && break || sleep $((i*10)); done
Defensive patterns

Strategy: fallback

Validate before calling

async fn gateway_serves(gateway: &str, cid: &str) -> bool {
    let url = format!("{gateway}/ipfs/{cid}?download=true");
    reqwest::Client::new()
        .get(&url)
        .send()
        .await
        .map(|r| r.status().is_success())
        .unwrap_or(false)
}
// before building: try gateways in order and configure the first healthy one

Prevention

When it happens

Trigger: The public IPFS gateway rate-limits or returns 429/5xx, the gateway is temporarily down, or the CID is invalid/unknown so the gateway returns an error status.

Common situations: CI builds hammering public gateways; corporate networks blocking IPFS gateways; typos in cids; gateway outages.

Related errors


AI-assisted analysis of FuelLabs/sway@47e5e902fa (2026-08-16). Data as JSON: /api/errors/6493bfe11498f00b. Report an issue: GitHub.