nautechsystems/nautilus_trader · error
custom data request requires `instrument_id` metadata
Error message
custom data request requires `instrument_id` metadata
What it means
A Binance Futures custom data request (DataCmd) must include `instrument_id` in its metadata map, so the adapter can resolve which instrument the request targets. `required_instrument_id_metadata` bails when the metadata is absent, empty, or whitespace.
Solutions
- Add `instrument_id` to the custom data request metadata as a non-empty string
- Ensure the value is a valid InstrumentId parseable by the adapter (e.g. BTCUSDT-PERP.BINANCE)
- Trim whitespace from the configured value
- Fix surrounding code if the metadata is a serde map being silently dropped (wrong serialization type)
Example fix
// before
let data_type = DataType::new("BinanceFuturesOpenInterestHist", None);
// after
let metadata = indexmap::IndexMap::from([("instrument_id".to_string(), serde_json::json!("BTCUSDT-PERP.BINANCE"))]);
let data_type = DataType::new("BinanceFuturesOpenInterestHist", Some(metadata)); Defensive patterns
Strategy: validation
Validate before calling
let id = data_type.metadata()
.and_then(|m| m.get("instrument_id"))
.and_then(|v| v.as_str())
.map(str::trim)
.filter(|s| !s.is_empty());
assert!(id.is_some(), "instrument_id metadata required"); Type guard
fn has_instrument_id(meta: &Option<IndexMap<String, serde_json::Value>>) -> bool {
meta.as_ref().and_then(|m| m.get("instrument_id")).and_then(|v| v.as_str()).map(str::trim).map_or(false, |s| !s.is_empty())
} Try / catch
match client.request_data(data_type).await {
Err(e) if e.to_string().contains("requires `instrument_id` metadata") => return Err(anyhow::anyhow!("add instrument_id metadata to request")),
other => other,
} Prevention
- Always include instrument_id in custom data metadata
- Use a shared builder function for custom DataCmds
- Trim configured instrument ids
When it happens
Trigger: Calling request_data with a custom data type (e.g. BinanceFuturesOpenInterestHist) whose DataType metadata either has no `instrument_id` key, has a non-string value, or a blank/whitespace string.
Common situations: Building a DataCmd programmatically and forgetting the metadata entry, copying example code without the metadata map, or passing an ID wrapped in quotes/whitespace.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Binance load_ids value
- Cannot write data with mixed identities: element has…
- historical open interest request requires `period` metadata
- invalid Binance load_ids value
- invalid negative kline trade count
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/96ae69b0f96d6adb.
Report an issue: GitHub.
Appendix: source
Thrown at crates/adapters/binance/src/futures/data.rs:476
return Ok(None);
};
let instrument_id = InstrumentId::from_str(raw_instrument_id)
.with_context(|| format!("invalid instrument_id metadata `{raw_instrument_id}`"))?;
Ok(Some(instrument_id))
}
fn required_instrument_id_metadata(data_type: &DataType) -> anyhow::Result<InstrumentId> {
let Some(raw_instrument_id) = data_type
.metadata()
.as_ref()
.and_then(|m| m.get("instrument_id"))
.and_then(|v| v.as_str())
.map(str::trim)
.filter(|value| !value.is_empty())
else {
anyhow::bail!("custom data request requires `instrument_id` metadata");
};
InstrumentId::from_str(raw_instrument_id)
.with_context(|| format!("invalid instrument_id metadata `{raw_instrument_id}`"))
}
fn required_period_metadata(data_type: &DataType) -> anyhow::Result<String> {
let Some(period) = data_type
.metadata()
.as_ref()
.and_then(|m| m.get("period"))
.and_then(|v| v.as_str())
.map(str::trim)
.filter(|value| !value.is_empty())
else {
anyhow::bail!("historical open interest request requires `period` metadata");
};
View on GitHub (pinned to 18893faf8b)