nautechsystems/nautilus_trader · error

Continuous future target {primary_bar_type} must be internal

Error message

Continuous future target {primary_bar_type} must be internally aggregated

What it means

The primary bar type of a continuous future request/subscription must be internally aggregated, since the engine builds the continuous series from its own aggregated bars. Externally aggregated targets cannot be stitched or adjusted by the roller, so parse_continuous_future rejects them.

Source

Thrown at crates/data/src/engine/requests.rs:372

        return Ok(None);
    }

    if params.contains_key(BAR_TYPES) {
        anyhow::bail!(
            "Continuous future bar subscriptions must not include `bar_types`; pass the chain in continuous_future_transitions instead"
        );
    }

    parse_continuous_future(vec![cmd.bar_type], params).map(Some)
}

fn parse_continuous_future(
    bar_types: Vec<BarType>,
    params: &Params,
) -> anyhow::Result<ContinuousFutureRequest> {
    let primary_bar_type = bar_types[0];
    if !primary_bar_type.is_internally_aggregated() {
        anyhow::bail!("Continuous future target {primary_bar_type} must be internally aggregated");
    }

    let transitions_value = params
        .get(CONTINUOUS_FUTURE_TRANSITIONS)
        .context("missing `continuous_future_transitions`")?;
    let adjustment_mode = parse_adjustment_mode(params.get(CONTINUOUS_FUTURE_ADJUSTMENT_MODE))
        .with_context(|| {
            format!("Invalid continuous future adjustment mode for {primary_bar_type}")
        })?;
    let first_pre_instrument_id = parse_optional_chain_bound(
        params,
        FIRST_PRE_INSTRUMENT_ID,
        primary_bar_type.instrument_id(),
    )?;
    let last_post_instrument_id = parse_optional_chain_bound(
        params,
        LAST_POST_INSTRUMENT_ID,
        primary_bar_type.instrument_id(),

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Construct the primary bar type with internal aggregation (omit the ':external' suffix or pass AggregationSource::Internal explicitly).
  2. Verify primary_bar_type.is_internally_aggregated() before invoking the continuous future API.
  3. If external bars are required, aggregate internally or bypass the continuous future pipeline.

Example fix

// before
let primary = BarType::new(id, spec, AggregationSource::External);
parse_continuous_future(vec![primary], &params)?;
// after
let primary = BarType::new(id, spec, AggregationSource::Internal);
parse_continuous_future(vec![primary], &params)?;
Defensive patterns

Strategy: validation

Validate before calling

if !primary_bar_type.is_internally_aggregated() {
    anyhow::bail!("continuous future primary must be internally aggregated");
}

Type guard

fn is_valid_continuous_primary(bt: &BarType) -> bool {
    bt.is_internally_aggregated()
}

Try / catch

match parse_continuous_future(bar_types, &params) {
    Err(e) if e.to_string().contains("must be internally aggregated") => {
        let bt = BarType::new(bar_types[0].instrument_id().clone(), bar_types[0].spec(), AggregationSource::Internal);
        parse_continuous_future(vec![bt], &params)?;
    }
    r => r,
}

Prevention

When it happens

Trigger: Calling subscribe_continuous_future_bars or a continuous future bars request where bar_types[0] has AggregationSource::External (is_internally_aggregated() == false).

Common situations: Bar type strings parsed with an external-aggregation suffix; adapters that emit pre-aggregated bars being reused for continuous futures; refactors that changed the aggregation source default.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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