{"record":{"id":"13fc8881bfe9a981","repo":"nautechsystems/nautilus_trader","slug":"unsupported-product-product-id-type-product","errorCode":null,"errorMessage":"Unsupported product '{product_id}' (type={product_type}, non_crypto={non_crypto})","messagePattern":"Unsupported product '(.+?)' \\(type=(.+?), non_crypto=(.+?)\\)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/coinbase/src/provider.rs","lineNumber":181,"sourceCode":"        self.client.record_product_aliases(&response.products);\n        Ok(instruments)\n    }\n\n    /// Parses a single product response and caches the instrument.\n    ///\n    /// Expects the JSON shape returned by `GET /products/{product_id}`.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the JSON cannot be deserialized or the product fails to parse.\n    pub fn load_from_product_response(\n        &self,\n        json: &serde_json::Value,\n    ) -> anyhow::Result<InstrumentAny> {\n        let product: Product =\n            serde_json::from_value(json.clone()).map_err(|e| anyhow::anyhow!(\"{e}\"))?;\n\n        anyhow::ensure!(\n            is_supported_product(&product),\n            \"Unsupported product '{}' (type={}, non_crypto={})\",\n            product.product_id,\n            product.product_type,\n            product\n                .future_product_details\n                .as_ref()\n                .is_some_and(|d| d.non_crypto),\n        );\n\n        let ts_init = self.client.ts_now();\n        let instrument = parse_instrument(&product, ts_init)?;\n\n        self.cache_instrument(&instrument);\n        self.client\n            .record_product_aliases(std::slice::from_ref(&product));\n\n        Ok(instrument)","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/coinbase/src/provider.rs#L163-L199","documentation":"Coinbase instrument loading rejects products that fail `is_supported_product` during deserialization from the /products REST response. The adapter only supports crypto spot products; futures and other non-crypto product types are intentionally not converted into Nautilus instruments. The message includes product id, type, and the future_product_details flag to pinpoint why it was rejected.","triggerScenarios":"Calling `load` / `load_from_product_response` with a Coinbase product JSON whose product_type is not a supported crypto type (e.g. FUTURE), or whose `future_product_details` is populated.","commonSituations":"Pointing the adapter at Coinbase products that include futures (e.g. PERP- or EXP- prefixed products like BTC-PERP-...), a Coinbase API version change adding new product types, or loading the full product universe instead of filtering to spot products.","solutions":["Filter Coinbase products before loading, keeping only supported crypto spot products","Check the product's product_type in the raw JSON and skip unsupported ones","Update the adapter's `is_supported_product` if a new legitimately supported product type was added upstream","Confirm you are using the spot Coinbase API/endpoint rather than one returning futures"],"exampleFix":"// before\nlet instrument = provider.load_from_product_response(&product_json)?;\n// after\nif !product_json[\"future_product_details\"].is_null() {\n    log::warn!(\"skipping non-spot product: {}\", product_json[\"product_id\"]);\n    continue;\n}\nlet instrument = provider.load_from_product_response(&product_json)?;","handlingStrategy":"validation","validationCode":"fn is_spot(product: &serde_json::Value) -> bool {\n    product[\"future_product_details\"].is_null()\n        && product[\"product_type\"] == \"SPOT\"\n}","typeGuard":"fn as_supported_product(json: &serde_json::Value) -> Option<&serde_json::Value> {\n    if json[\"future_product_details\"].is_null() { Some(json) } else { None }\n}","tryCatchPattern":"match provider.load_from_product_response(&json) {\n    Ok(instrument) => cache.add(instrument),\n    Err(e) if e.to_string().contains(\"Unsupported product\") => log::debug!(\"skipped: {e}\"),\n    Err(e) => return Err(e),\n}","preventionTips":["Request/filter only spot products from the Coinbase products endpoint","Log and skip unsupported product types instead of treating them as fatal","Pin or review the Coinbase API version so product_type enums stay stable"],"tags":["coinbase","instrument","unsupported-product"],"backgroundTag":"unsupported-enum-value","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"}