{"record":{"id":"4bb23f2039096820","repo":"nautechsystems/nautilus_trader","slug":"cannot-extract-selection-id-from-instrument-id","errorCode":null,"errorMessage":"Cannot extract selection ID from {instrument_id}","messagePattern":"Cannot extract selection ID from (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/betfair/src/common/parse.rs","lineNumber":522,"sourceCode":"    if parts.len() >= 2 {\n        Ok(parts[0].to_string())\n    } else {\n        anyhow::bail!(\"Cannot extract market ID from {instrument_id}\")\n    }\n}\n\n/// Extracts the selection ID and handicap from a Nautilus instrument ID.\n///\n/// # Errors\n///\n/// Returns an error if the symbol cannot be parsed into the expected format.\npub fn extract_selection_id(\n    instrument_id: &InstrumentId,\n) -> anyhow::Result<(SelectionId, Decimal)> {\n    let symbol = instrument_id.symbol.as_str();\n    let parts: Vec<&str> = symbol.splitn(3, '-').collect();\n    if parts.len() < 2 {\n        anyhow::bail!(\"Cannot extract selection ID from {instrument_id}\");\n    }\n\n    let selection_id: SelectionId = parts[1]\n        .parse()\n        .with_context(|| format!(\"invalid selection ID in {instrument_id}\"))?;\n\n    let handicap = if parts.len() == 3 {\n        parts[2]\n            .parse::<Decimal>()\n            .with_context(|| format!(\"invalid handicap in {instrument_id}\"))?\n    } else {\n        Decimal::ZERO\n    };\n\n    Ok((selection_id, handicap))\n}\n\n#[cfg(test)]","sourceCodeStart":504,"sourceCodeEnd":540,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/a4b06ed870971b5671d12754ea138a3ab99b1dec/crates/adapters/betfair/src/common/parse.rs#L504-L540","documentation":"extract_selection_id splits the instrument symbol on '-' (max 3 parts) and parses part 2 as the SelectionId (u64) and, if present, part 3 as the handicap Decimal. With fewer than 2 segments there is no selection component and it bails before parsing. Malformed numeric parts fail later with separate 'invalid selection ID' / 'invalid handicap' messages.","triggerScenarios":"An InstrumentId whose symbol lacks a hyphen separator — bare market id (1.246503964), a foreign venue symbol routed to Betfair, or a hand-built string like \"mymarket\" — reaches order submission (submit/cancel paths call extract_selection_id after extract_market_id).","commonSituations":"Replaying recorded instruments through a different venue config; config files or env vars truncating the symbol at the hyphen; integrations that map their own selection keys directly into symbols without the market-id prefix.","solutions":["Build ids with make_instrument_id so market id, selection id, and handicap are always present","Pre-validate the symbol has at least 2 hyphen-separated parts and the second parses as u64 before calling execution APIs","Verify the instrument definition being traded actually came from the Betfair adapter (venue check)","Fix the upstream mapping that produced the truncated or foreign symbol"],"exampleFix":"// before\nlet id = InstrumentId::from(\"1.246503964.BETFAIR\");\nlet (sel, hcp) = extract_selection_id(&id)?; // fails: no '-selection' part\n// after\nlet id = make_instrument_id(\"1.246503964\", 12345, Decimal::ZERO);\nlet (sel, hcp) = extract_selection_id(&id)?;","handlingStrategy":"validation","validationCode":"// Validate symbol shape before calling APIs that need selection extraction\nfn symbol_has_selection(id: &InstrumentId) -> bool {\n    let parts: Vec<&str> = id.symbol.as_str().splitn(3, '-').collect();\n    parts.len() >= 2 && parts[1].parse::<u64>().is_ok()\n}\n\nif !symbol_has_selection(&instrument_id) {\n    anyhow::bail!(\"instrument {instrument_id} lacks a '-selection' component\");\n}","typeGuard":null,"tryCatchPattern":"match extract_selection_id(&instrument_id) {\n    Ok((selection_id, handicap)) => submit_order(market_id, selection_id, handicap).await,\n    Err(e) => {\n        log::error!(\"cannot extract selection from {instrument_id}: {e}\");\n        // fail the command explicitly so the strategy can drop or re-route the order\n        Err(e)\n    }\n}","preventionTips":["Round-trip new instruments through make_instrument_id + extract_selection_id in tests to prove the format survives","Guard against config/env truncation at hyphens — quote symbols in configs and unit-test parsing","Keep instrument ids opaque: pass InstrumentId objects end-to-end instead of rebuilding them from strings"],"tags":["betfair","instrument-id","parsing","symbol-format","execution"],"backgroundTag":"instrument-id-parse-error","analyzedSha":"a4b06ed870971b5671d12754ea138a3ab99b1dec","analyzedAt":"2026-08-16T22:54:50.089Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}