nautechsystems/nautilus_trader · error
Expected 2 outcomes, received {}
Error message
Expected 2 outcomes, received {} What it means
parse_gamma_market requires the market's outcomes JSON array to contain exactly two outcomes, matching the two CLOB token IDs of a binary market. Any other count aborts the parse because instrument construction assumes a YES/NO pair.
Source
Thrown at crates/adapters/polymarket/src/http/parse.rs:125
.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);
let taker_fee: Option<Decimal> = market.fee_schedule.as_ref().map(|fs| fs.rate);
let min_size = market.order_min_size;
let active = market.active.unwrap_or(false)
&& !market.closed.unwrap_or(false)
&& market.accepting_orders.unwrap_or(false);View on GitHub (pinned to 18893faf8b)
Solutions
- Pre-filter markets to those with exactly two outcomes before parsing into instruments.
- Skip and log the offending market.condition_id so one bad market does not fail the whole batch.
- Verify the raw outcomes JSON from the Gamma API to detect schema changes.
- Handle multi-outcome events with dedicated parsing logic if support is needed.
Example fix
// before
if outcomes.len() != 2 {
anyhow::bail!("Expected 2 outcomes, received {}", outcomes.len());
}
// after (caller-side guard)
let outcomes: Vec<String> = serde_json::from_str(&market.outcomes)?;
if outcomes.len() != 2 { log::warn!("skipping non-binary market {}", market.condition_id); continue; } Defensive patterns
Strategy: validation
Validate before calling
fn has_two_outcomes(m: &GammaMarket) -> bool {
serde_json::from_str::<Vec<String>>(&m.outcomes)
.map(|o| o.len() == 2)
.unwrap_or(false)
}
// filter: markets.retain(has_two_outcomes); Type guard
fn is_binary_outcomes(raw: &str) -> bool {
matches!(serde_json::from_str::<Vec<String>>(raw), Ok(v) if v.len() == 2)
} Try / catch
let outcomes: Vec<String> = serde_json::from_str(&market.outcomes)?;
if outcomes.len() != 2 {
log::warn!("skipping market {} with {} outcomes", market.condition_id, outcomes.len());
return Ok(None); // skip instead of failing batch
} Prevention
- Pre-filter markets to binary (2-outcome) ones before parsing.
- Combine outcome and token-id count checks into one guard.
- Test parsing against real Gamma payloads in CI.
When it happens
Trigger: A Gamma market whose outcomes field deserializes to fewer or more than 2 strings (multi-outcome markets, empty outcomes arrays, malformed outcomes JSON).
Common situations: Fetching sports or neg-risk multi-outcome events where a market can list several outcomes; API responses for very new markets with empty outcome arrays; Gamma API payload drift.
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 token IDs, 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/2e306df93091de24.
Report an issue: GitHub.