nautechsystems/nautilus_trader · error

Invalid `OptionKind`, was '{invalid}'

Error message

Invalid `OptionKind`, was '{invalid}'

What it means

parse_option_kind maps a Databento option-kind character (the call/put discriminant) to an OptionKind; any character outside the valid discriminant set fails here before the option contract is decoded.

Source

Thrown at crates/adapters/databento/src/decode/primitives.rs:85

        'R' => Ok(BookAction::Clear),
        // 'F' (Fill) and 'N' (None) are deliberately NOT book actions: fills
        // are attribution records whose book impact arrives as the explicit
        // Cancel/Modify of the same match event (`decode_mbo_msg` filters
        // them out before calling this).
        invalid => anyhow::bail!("Invalid `BookAction`, was '{invalid}'"),
    }
}

/// Parses a Databento option kind character into an `OptionKind` enum.
///
/// # Errors
///
/// Returns an error if `c` is not a valid `OptionKind` character.
pub fn parse_option_kind(c: c_char) -> anyhow::Result<OptionKind> {
    match c as u8 as char {
        'C' => Ok(OptionKind::Call),
        'P' => Ok(OptionKind::Put),
        invalid => anyhow::bail!("Invalid `OptionKind`, was '{invalid}'"),
    }
}

pub(super) fn parse_currency_or_usd_default(
    value: Result<&str, impl std::error::Error>,
) -> Currency {
    match value {
        Ok(value) if !value.is_empty() => Currency::try_from_str(value).unwrap_or_else(|| {
            log::warn!("Unknown currency code '{value}', defaulting to USD");
            Currency::USD()
        }),
        Ok(_) => Currency::USD(),
        Err(e) => {
            log::warn!("Error parsing currency: {e}");
            Currency::USD()
        }
    }
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify the instrument definition's option_kind field is 'C' or 'P'
  2. Check that the record really is an option contract (asset class / instrument_class)
  3. Fix or regenerate corrupted definition data from Databento
  4. Normalize case upstream if your data uses lowercase c/p

Example fix

// before
option_kind: b'c'
// after
option_kind: b'C' // 'C' call or 'P' put only
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_option_kind(c: u8) -> bool { matches!(c, b'C' | b'P') }
fn validate_definition(def: &dbn::InstrumentDefMsg) -> Result<(), String> {
    if def.instrument_class == dbn::InstrumentClass::Option && !is_valid_option_kind(def.option_kind as u8) {
        return Err(format!("bad option_kind: {}", def.option_kind));
    }
    Ok(())
}

Type guard

fn is_call_or_put(c: u8) -> Option<OptionKindSide> { match c { b'C' => Some(Call), b'P' => Some(Put), _ => None } }

Try / catch

match decode_option_contract(def) {
    Ok(c) => c,
    Err(e) if e.to_string().contains("Invalid `OptionKind`") => { /* skip non-option/malformed record */ }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Decoding an option contract definition whose `option_kind` field is neither 'C' nor 'P' (e.g. empty, 'c'/'p' lowercase, or a placeholder char).

Common situations: Malformed instrument definition records; upstream schema changes; manually constructed test definitions with the wrong kind character; non-option records accidentally routed through option decoding.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/c05ced7094d9401b. Report an issue: GitHub.