{"record":{"id":"8fde3286199262be","repo":"nautechsystems/nautilus_trader","slug":"unknown-product-type-for-product-id","errorCode":null,"errorMessage":"Unknown product type for '{product_id}'","messagePattern":"Unknown product type for '(.+?)'","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/coinbase/src/http/parse.rs","lineNumber":323,"sourceCode":"        .build()\n        .unwrap();\n\n    Ok(InstrumentAny::CryptoFuture(instrument))\n}\n\n/// Parses a Coinbase product into the appropriate Nautilus instrument type.\npub fn parse_instrument(product: &Product, ts_init: UnixNanos) -> anyhow::Result<InstrumentAny> {\n    match product.product_type {\n        CoinbaseProductType::Spot => parse_spot_instrument(product, ts_init),\n        CoinbaseProductType::Future => {\n            if is_perpetual_product(product) {\n                parse_perpetual_instrument(product, ts_init)\n            } else {\n                parse_future_instrument(product, ts_init)\n            }\n        }\n        CoinbaseProductType::Unknown => {\n            anyhow::bail!(\"Unknown product type for '{}'\", product.product_id)\n        }\n    }\n}\n\n/// Determines whether a futures product is a perpetual contract.\n///\n/// Coinbase returns `contract_expiry_type: \"EXPIRING\"` for both perpetuals\n/// and dated futures, so the `CoinbaseContractExpiryType::Perpetual` variant\n/// alone is not sufficient. We check three signals in order:\n///\n/// 1. `contract_expiry_type == Perpetual` (forward compat if Coinbase fixes the API)\n/// 2. Non-empty `funding_rate` in `future_product_details` (structural signal:\n///    only perpetuals have ongoing funding)\n/// 3. `display_name` contains \"PERP\" or \"Perpetual\" (heuristic fallback)\npub(crate) fn is_perpetual_product(product: &Product) -> bool {\n    if let Some(details) = &product.future_product_details {\n        if details.contract_expiry_type == CoinbaseContractExpiryType::Perpetual {\n            return true;","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/coinbase/src/http/parse.rs#L305-L341","documentation":"parse_instrument maps each Coinbase product to a Nautilus instrument based on its CoinbaseProductType (SPOT, FUTURE, PERPETUAL). When a product carries the Unknown product type, the parser cannot determine which instrument constructor to use and fails with this error naming the product_id.","triggerScenarios":"Requesting instruments via request_instruments/request_instrument and Coinbase returns a product whose product_type field deserializes to Unknown (new asset classes, unusual product listings, or API schema changes).","commonSituations":"Coinbase adds a new product category before the adapter enum is updated; calling request_instrument on a product_id for a product type the adapter does not model (e.g. certain derivatives listings).","solutions":["Check the product_id on Coinbase's API and confirm it is a supported SPOT/FUTURE/PERPETUAL product","Update CoinbaseProductType and parse_instrument to support the new product type if Coinbase introduced one","Skip/filter Unknown products when bulk-loading instruments"],"exampleFix":"// before\nlet inst = client.request_instrument(\"BTC-JAM-UNKNOWN\").await?;\n// after\nlet products: Vec<_> = all.filter(|p| p.product_type != CoinbaseProductType::Unknown).collect();","handlingStrategy":"type-guard","validationCode":"if product.product_type == CoinbaseProductType::Unknown {\n    log::warn!(\"skipping unsupported product {}\", product.product_id);\n    return Ok(None);\n}","typeGuard":"fn is_supported_product(p: &CoinbaseProduct) -> bool {\n    !matches!(p.product_type, CoinbaseProductType::Unknown)\n}","tryCatchPattern":null,"preventionTips":["Filter products by supported product_type before parsing","Keep the adapter's product-type enum updated with Coinbase API changes","Whitelist product_ids in config rather than loading everything"],"tags":["rust","coinbase","instruments","parsing"],"backgroundTag":"unexpected-api-response-shape","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"}