nautechsystems/nautilus_trader · error
No option expirations for {currency}
Error message
No option expirations for {currency} What it means
After fetching expirations, request_option_expirations looks up the per-currency entry via expirations_for_currency and requires its `option` expirations. When the currency key is missing from the response map there is no Option expirations list, so the call fails. This is a lookup miss on a response that did return a result.
Source
Thrown at crates/adapters/deribit/src/http/client.rs:1955
/// # Errors
///
/// Returns an error if the request fails.
pub async fn request_option_expirations(
&self,
currency: DeribitCurrency,
) -> anyhow::Result<Vec<String>> {
let params = GetExpirationsParams::new(currency.as_str(), DeribitExpirationKind::Option);
let full_response = self
.inner
.get_expirations(params)
.await
.map_err(|e| anyhow::anyhow!(e))?;
let response = full_response
.result
.ok_or_else(|| anyhow::anyhow!("No result in expirations response"))?;
let expirations = response
.expirations_for_currency(currency.as_str())
.ok_or_else(|| anyhow::anyhow!("No option expirations for {currency}"))?;
Ok(expirations.option.clone())
}
/// Requests position status reports for reconciliation.
///
/// Fetches positions from Deribit and converts them to Nautilus [`PositionStatusReport`].
///
/// # Strategy
/// - Uses `currency=any` to fetch all positions in one call
/// - Filters by instrument_id if provided
///
/// # Errors
///
/// Returns an error if the request fails or parsing fails.
pub async fn request_position_status_reports(
&self,
account_id: AccountId,View on GitHub (pinned to 18893faf8b)
Solutions
- Use the canonical uppercase Deribit currency code matching the response keys.
- Confirm the currency actually lists option instruments; otherwise handle the absence gracefully.
- Log available keys from the response to see which currencies were returned.
Example fix
// before
let expirations = response
.expirations_for_currency(currency.as_str())
.ok_or_else(|| anyhow::anyhow!("No option expirations for {currency}"))?;
// after
let expirations = response.expirations_for_currency(currency.as_str()).ok_or_else(|| {
anyhow::anyhow!(
"No option expirations for {currency}; available: {:?}",
response.available_currencies()
)
})?; Defensive patterns
Strategy: fallback
Validate before calling
// Guard against non-canonical currency strings before the call let currency = currency.to_uppercase(); assert!(!currency.is_empty());
Try / catch
match client.request_option_expirations(currency).await {
Ok(x) => handle(x),
Err(e) if e.to_string().contains("No option expirations for") => Vec::new(), // fall back to empty
Err(e) => return Err(e),
} Prevention
- Normalize currency strings (uppercase, no whitespace) before lookup
- Treat missing option expirations as an expected empty case for currencies without options
- Log available currencies from the response when a lookup misses
When it happens
Trigger: Calling request_option_expirations(currency) where the returned expirations map has no entry for that exact currency string (case mismatch or currency not present in the payload).
Common situations: Passing a lowercase or non-canonical currency symbol, or a currency that lists expirations only for futures but not options.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- No result in ticker response
- No result in book summary response
- No result in expirations response
- No margin data returned from BitMEX
- Order rejected: {reason}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/96ecbe5899524816.
Report an issue: GitHub.