{"record":{"id":"96ae69b0f96d6adb","repo":"nautechsystems/nautilus_trader","slug":"custom-data-request-requires-instrument-id-metad","errorCode":null,"errorMessage":"custom data request requires `instrument_id` metadata","messagePattern":"custom data request requires `instrument_id` metadata","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/binance/src/futures/data.rs","lineNumber":432,"sourceCode":"            return Ok(None);\n        };\n\n        let instrument_id = InstrumentId::from_str(raw_instrument_id)\n            .with_context(|| format!(\"invalid instrument_id metadata `{raw_instrument_id}`\"))?;\n\n        Ok(Some(instrument_id))\n    }\n\n    fn required_instrument_id_metadata(data_type: &DataType) -> anyhow::Result<InstrumentId> {\n        let Some(raw_instrument_id) = data_type\n            .metadata()\n            .as_ref()\n            .and_then(|m| m.get(\"instrument_id\"))\n            .and_then(|v| v.as_str())\n            .map(str::trim)\n            .filter(|value| !value.is_empty())\n        else {\n            anyhow::bail!(\"custom data request requires `instrument_id` metadata\");\n        };\n\n        InstrumentId::from_str(raw_instrument_id)\n            .with_context(|| format!(\"invalid instrument_id metadata `{raw_instrument_id}`\"))\n    }\n\n    fn required_period_metadata(data_type: &DataType) -> anyhow::Result<String> {\n        let Some(period) = data_type\n            .metadata()\n            .as_ref()\n            .and_then(|m| m.get(\"period\"))\n            .and_then(|v| v.as_str())\n            .map(str::trim)\n            .filter(|value| !value.is_empty())\n        else {\n            anyhow::bail!(\"historical open interest request requires `period` metadata\");\n        };\n","sourceCodeStart":414,"sourceCodeEnd":450,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/a4b06ed870971b5671d12754ea138a3ab99b1dec/crates/adapters/binance/src/futures/data.rs#L414-L450","documentation":"Binance futures custom data types (liquidation stream 'BinanceFuturesLiquidation', open interest history, mark-price style requests) are identified by metadata on the DataType rather than by the type name alone. required_instrument_id_metadata bails when the metadata map lacks a non-empty 'instrument_id' string, because the request cannot be scoped to a symbol without it.","triggerScenarios":"Calling subscribe / request on the futures data client with a hand-built DataType for a Binance custom stream that omits metadata, e.g. DataType('BinanceFuturesLiquidation') with no metadata, or metadata={'instrument_id': ''} / a non-string value.","commonSituations":"Constructing the custom DataType manually instead of using the adapter's provided request/subscription helpers; passing metadata keys with different names ('symbol', 'instrument'); trailing-whitespace or empty-string instrument_id from templated configs.","solutions":["Include a metadata entry 'instrument_id' with the full instrument ID string, e.g. metadata={'instrument_id': 'BTCUSDT-PERP.BINANCE'}.","Prefer the adapter's higher-level subscribe/request methods which build the DataType (and its metadata) for you, mirroring liquidation_data_type() in futures/data.rs.","Verify the value parses as an InstrumentId (SYMBOL.VENUE) since an invalid string fails with the adjacent 'invalid instrument_id metadata' context error."],"exampleFix":"# before\nfrom nautilus_trader.core.data import Data\nclient.subscribe(DataType('BinanceFuturesLiquidation'))\n\n# after\nmetadata = {'instrument_id': 'BTCUSDT-PERP.BINANCE'}\nclient.subscribe(DataType('BinanceFuturesLiquidation', metadata=metadata))","handlingStrategy":"validation","validationCode":"def custom_data_with_instrument(data_type_name: str, instrument_id: str) -> 'DataType':\n    assert instrument_id and '.' in instrument_id  # SYMBOL.VENUE\n    return DataType(data_type_name, metadata={'instrument_id': instrument_id})\n\n# usage\nclient.subscribe(custom_data_with_instrument('BinanceFuturesLiquidation', 'BTCUSDT-PERP.BINANCE'))","typeGuard":"def has_required_custom_metadata(data_type) -> bool:\n    md = dict(data_type.metadata or {})\n    return isinstance(md.get('instrument_id'), str) and bool(md['instrument_id'].strip())","tryCatchPattern":"try:\n    client.subscribe(data_type)\nexcept Exception as e:\n    if 'requires `instrument_id` metadata' in str(e):\n        data_type = DataType(data_type.topic, metadata={'instrument_id': 'BTCUSDT-PERP.BINANCE'})\n        client.subscribe(data_type)\n    else:\n        raise","preventionTips":["Use the adapter's built-in subscribe/request helpers for Binance custom streams instead of hand-built DataTypes.","Always include metadata={'instrument_id': '<SYMBOL.VENUE>'} on custom Binance data types.","Add open-interest history requests also need 'period' metadata — set both up front."],"tags":["binance","futures","custom-data","metadata","subscription","validation"],"backgroundTag":"missing-required-parameter","analyzedSha":"a4b06ed870971b5671d12754ea138a3ab99b1dec","analyzedAt":"2026-08-16T22:54:50.089Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}