nautechsystems/nautilus_trader · error
Failed to fetch product '{product_id}': {e}
Error message
Failed to fetch product '{product_id}': {e} What it means
Raised by request_instrument when get_product(product_id) fails for the given product. The HTTP client error is wrapped with the offending product_id, so the caller knows which instrument lookup failed before any parsing occurs.
Source
Thrown at crates/adapters/coinbase/src/http/client.rs:1072
self.cache_instruments(&instruments);
self.record_product_aliases(&response.products);
Ok(instruments)
}
/// Requests a single instrument by product ID.
///
/// Caches the result on success.
///
/// # Errors
///
/// Returns an error when the HTTP request fails, deserialization fails,
/// or the product cannot be parsed into a supported instrument.
pub async fn request_instrument(&self, product_id: &str) -> anyhow::Result<InstrumentAny> {
let json = self
.inner
.get_product(product_id)
.await
.map_err(|e| anyhow::anyhow!("Failed to fetch product '{product_id}': {e}"))?;
let product: crate::http::models::Product =
serde_json::from_value(json).map_err(|e| anyhow::anyhow!(e))?;
let ts_init = self.ts_now();
let instrument = parse_instrument(&product, ts_init)?;
self.cache_instrument(&instrument);
self.record_product_aliases(std::slice::from_ref(&product));
Ok(instrument)
}
/// Requests the raw product payload for a product ID.
///
/// Returns the full [`crate::http::models::Product`] so callers can read
/// derivatives-specific fields (`future_product_details.index_price`,
/// `funding_rate`, `funding_time`) that are stripped when parsing to a
/// Nautilus instrument.
///
/// # Errors
///View on GitHub (pinned to 18893faf8b)
Solutions
- Verify the product_id exists on Coinbase Advanced Trade (use request_instruments to list valid ids).
- Check the wrapped error for 404 (invalid/delisted product) vs 5xx (retry with backoff).
- Retry transient failures with exponential backoff.
- Pre-populate the instrument cache via request_instruments so get_or_fetch_instrument does not hit this path.
Example fix
// before
let inst = client.request_instrument("BTC-USD").await?;
// after (validate id first)
let valid = client.request_instruments(None).await?;
anyhow::ensure!(valid.iter().any(|i| i.id().as_str() == "BTC-USD"), "unknown product");
let inst = client.request_instrument("BTC-USD").await?; Defensive patterns
Strategy: validation
Validate before calling
let known: Vec<InstrumentAny> = client.request_instruments(None).await?;
anyhow::ensure!(
known.iter().any(|i| i.id().as_str() == product_id),
"product {product_id} not listed on Coinbase"
); Try / catch
match client.request_instrument(product_id).await {
Ok(i) => i,
Err(e) if e.to_string().contains("404") => bail!("delisted/unknown product {product_id}"),
Err(e) => { backoff_retry(|| client.request_instrument(product_id)).await? }
} Prevention
- Validate product ids against the /products list before single-instrument lookups.
- Cache instruments up front so get_or_fetch_instrument avoids network calls.
- Distinguish 404 (fatal) from 5xx/429 (retryable) when handling the error.
When it happens
Trigger: Calling request_instrument(product_id) where the REST GET /products/{id} call fails: unknown product id (404), network error, rate limit, or auth problem.
Common situations: Typo'd or delisted product id (e.g. 'BTC-USD' vs 'BTC-USDC'), instruments that no longer exist on Coinbase, temporary network/API issues during bootstrap, callers like get_or_fetch_instrument resolving cache misses.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- Failed to fetch products: {e}
- Failed to fetch orders: {e}
- Unsupported instrument type: {} (kind: {:?})
- Failed to fetch accounts: {e}
- Failed to fetch order: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/1e303ccaf0d972dc.
Report an issue: GitHub.