nautechsystems/nautilus_trader · error
Expected 2 token IDs, received {}
Error message
Expected 2 token IDs, received {} What it means
parse_gamma_market requires Polymarket binary markets to have exactly two CLOB token IDs (one per outcome). The raw clob_token_ids JSON string is deserialized; if it yields a count other than 2 the parse fails. This invariant underpins mapping token IDs to YES/NO outcome instruments.
Source
Thrown at crates/adapters/polymarket/src/http/parse.rs:118
/// and one for the No outcome.
pub fn parse_gamma_market(market: &GammaMarket) -> anyhow::Result<Vec<PolymarketInstrumentDef>> {
let game_id = market.game_id.clone().or_else(|| {
market
.events
.as_ref()?
.iter()
.find_map(|event| event.game_id.clone())
});
let token_ids: Vec<String> = serde_json::from_str(&market.clob_token_ids).map_err(|e| {
anyhow::anyhow!(
"Failed to parse clob_token_ids '{}': {e}",
market.clob_token_ids
)
})?;
if token_ids.len() != 2 {
anyhow::bail!("Expected 2 token IDs, received {}", token_ids.len());
}
let outcomes: Vec<String> = serde_json::from_str(&market.outcomes)
.map_err(|e| anyhow::anyhow!("Failed to parse outcomes '{}': {e}", market.outcomes))?;
if outcomes.len() != 2 {
anyhow::bail!("Expected 2 outcomes, received {}", outcomes.len());
}
let tick_size = market
.order_price_min_tick_size
.unwrap_or(DEFAULT_TICK_SIZE);
let price_precision = POLYMARKET_PRICE_PRECISION;
// Polymarket charges fees using `feeSchedule.rate` on the Gamma market.
// Only takers pay; makers are always zero.
// Reference: https://docs.polymarket.com/trading/fees
let maker_fee: Option<Decimal> = market.fee_schedule.as_ref().map(|_| Decimal::ZERO);View on GitHub (pinned to 18893faf8b)
Solutions
- Filter out markets with non-binary clob_token_ids before calling parse_markets_to_instruments.
- Check whether the market belongs to a neg-risk/multi-outcome event and handle those markets separately.
- Log the offending market.condition_id and clob_token_ids payload to confirm the API response shape.
- Update the parsing code if Polymarket introduced a new market type requiring more than two tokens.
Example fix
// before
let markets: Vec<GammaMarket> = fetch_all(event);
// after
let markets: Vec<GammaMarket> = fetch_all(event)
.into_iter()
.filter(|m| serde_json::from_str::<Vec<String>>(&m.clob_token_ids).map(|t| t.len() == 2).unwrap_or(false))
.collect(); Defensive patterns
Strategy: validation
Validate before calling
fn has_two_token_ids(m: &GammaMarket) -> bool {
serde_json::from_str::<Vec<String>>(&m.clob_token_ids)
.map(|t| t.len() == 2)
.unwrap_or(false)
}
// filter: markets.retain(has_two_token_ids); Type guard
fn is_binary_token_count(raw: &str) -> bool {
matches!(serde_json::from_str::<Vec<String>>(raw), Ok(v) if v.len() == 2)
} Try / catch
match parse_gamma_market(&market, ts_init) {
Ok(instrument) => instruments.push(instrument),
Err(e) if e.to_string().starts_with("Expected 2 token IDs") => {
log::warn!("skipping non-binary market {}: {e}", market.condition_id);
}
Err(e) => return Err(e),
} Prevention
- Skip neg-risk/multi-outcome events when requesting binary instruments.
- Log skipped market condition_ids for observability.
- Pin/verify Gamma API response shape in integration tests.
When it happens
Trigger: A Gamma market record whose clob_token_ids field deserializes to 0, 1, or 3+ token IDs (e.g. neg-risk multi-outcome markets, empty clob_token_ids, malformed JSON that still parses to a wrong-length array).
Common situations: Querying multi-outcome/neg-risk events where markets legitimately have more than two tokens; new/unresolved markets with empty token arrays; Gamma API schema changes.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Expected 2 outcomes, received {}
- Failed to parse clob_token_ids '{}': {e}
- Failed to parse outcomes '{}': {e}
- fee exponent must be a decimal number or numeric string
- RTDS WebSocket client unavailable after reconcile
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/96e8fbfbd343b851.
Report an issue: GitHub.