{"record":{"id":"222a54b6200fd28d","repo":"nautechsystems/nautilus_trader","slug":"failed-to-fetch-product-product-id-e-222a54","errorCode":null,"errorMessage":"Failed to fetch product '{product_id}': {e}","messagePattern":"Failed to fetch product '(.+?)': (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/coinbase/src/provider.rs","lineNumber":113,"sourceCode":"            .client\n            .get_products()\n            .await\n            .map_err(|e| anyhow::anyhow!(\"Failed to fetch products: {e}\"))?;\n\n        self.load_from_products_response_filtered(&json, product_type)\n    }\n\n    /// Loads a single instrument by product ID from the REST API.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the HTTP request fails or the response cannot be parsed.\n    pub async fn load(&self, product_id: &str) -> anyhow::Result<InstrumentAny> {\n        let json = self\n            .client\n            .get_product(product_id)\n            .await\n            .map_err(|e| anyhow::anyhow!(\"Failed to fetch product '{product_id}': {e}\"))?;\n\n        self.load_from_product_response(&json)\n    }\n\n    /// Parses a products list response and caches the instruments.\n    ///\n    /// Expects the JSON shape returned by `GET /products`: `{\"products\": [...]}`.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the JSON cannot be deserialized or any product fails to parse.\n    pub fn load_from_products_response(\n        &self,\n        json: &serde_json::Value,\n    ) -> anyhow::Result<Vec<InstrumentAny>> {\n        let response: ProductsResponse =\n            serde_json::from_value(json.clone()).map_err(|e| anyhow::anyhow!(\"{e}\"))?;\n","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/coinbase/src/provider.rs#L95-L131","documentation":"CoinbaseInstrumentProvider::load fetches a single product by ID via get_product(product_id). Any client-side failure — unknown product returning 404, invalid ID, auth errors, network faults — is wrapped with the product ID for context. The error message includes the requested product_id so you can see exactly which lookup failed.","triggerScenarios":"Calling load(product_id) with an unknown/typo'd product ID (404), a delisted product, invalid credentials, network failure, or timeout on the single-product endpoint.","commonSituations":"Hard-coded product IDs using the wrong format (e.g. 'BTC-USD' vs Coinbase's 'BTC-USDC' or a canonical vs alias id); querying a product after it was delisted; missing auth for endpoints that need it.","solutions":["Verify the product_id exists via the products list (load_all or the REST products endpoint).","Check the inner error for 404 (bad/delisted id) vs 401 (auth) vs transport failure.","Use a canonical product id resolved through the provider's alias map if subscribing with an alias.","Retry transient network/5xx failures with backoff."],"exampleFix":"// before\nlet btc = provider.load(\"BTC-USD\").await?;\n// after\nlet btc = match provider.load(\"BTC-USD\").await {\n    Ok(i) => i,\n    Err(e) if e.to_string().contains(\"404\") => {\n        eprintln!(\"product not found; available ids: {:?}\", list_ids());\n        return Err(e);\n    }\n    Err(e) => return Err(e),\n};","handlingStrategy":"validation","validationCode":"let known: HashSet<String> = provider.load_all().await?.iter().map(|i| i.id().to_string()).collect();\nanyhow::ensure!(known.contains(\"BTC-USD\"), \"product BTC-USD not listed on Coinbase\");\nlet btc = provider.load(\"BTC-USD\").await?;","typeGuard":null,"tryCatchPattern":"match provider.load(product_id).await {\n    Ok(i) => i,\n    Err(e) if e.to_string().contains(\"404\") => { warn!(\"{product_id} not found/delisted\"); fallback_to_cached(product_id) }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Validate product IDs against the products list before single-product lookups.","Cache previously loaded instruments to survive transient/delisted lookups.","Use canonical IDs (via the adapter's alias map), not venue-agnostic symbols."],"tags":["http","coinbase","instrument-provider","not-found"],"backgroundTag":"http-error-response","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}