nautechsystems/nautilus_trader · error

Only EXTERNAL aggregation is supported

Error message

Only EXTERNAL aggregation is supported

What it means

request_bars only supports bars whose AggregationSource is External, i.e. bars the exchange (Deribit's TradingView chart data endpoint) produces. Internally aggregated bar types would require the client to build bars from raw trades, which it does not do, so anyhow::ensure! rejects them up front.

Source

Thrown at crates/adapters/deribit/src/http/client.rs:1374

    /// # Errors
    ///
    /// Returns an error if:
    /// - Aggregation source is not EXTERNAL
    /// - Bar aggregation type is not supported by Deribit
    /// - The instrument is not found in cache
    /// - The request fails or response cannot be parsed
    ///
    /// # Supported Resolutions
    ///
    /// Deribit supports: 1, 3, 5, 10, 15, 30, 60, 120, 180, 360, 720 minutes, and 1D (daily)
    pub async fn request_bars(
        &self,
        bar_type: BarType,
        start: Option<Timestamp>,
        end: Option<Timestamp>,
        limit: Option<u32>,
    ) -> anyhow::Result<Vec<Bar>> {
        anyhow::ensure!(
            bar_type.aggregation_source() == AggregationSource::External,
            "Only EXTERNAL aggregation is supported"
        );

        let now = Timestamp::now();

        // Default to last hour if no start/end provided
        let end_dt = end.unwrap_or(now);
        let start_dt = start.unwrap_or(end_dt - jiff::SignedDuration::from_hours(1));

        if let (Some(s), Some(e)) = (start, end) {
            anyhow::ensure!(s < e, "Invalid time range: start={s:?} end={e:?}");
        }

        // Convert BarType to Deribit resolution
        let spec = bar_type.spec();
        let step = spec.step.get();
        let resolution = match spec.aggregation {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Change the BarType to AggregationSource::External, e.g. BarType::from_spec with `BarAggregationSource::External`.
  2. If internal aggregation is required, aggregate locally from trades/bars streamed over websocket instead of calling request_bars.
  3. Check the BarType string/spec in config so it reads ...*EXTERNAL.

Example fix

// before
let bar_type = BarType::new(instrument_id, BarAggregation::Minute, 1, PriceType::Last, AggregationSource::Internal);
// after
let bar_type = BarType::new(instrument_id, BarAggregation::Minute, 1, PriceType::Last, AggregationSource::External);
Defensive patterns

Strategy: validation

Validate before calling

if bar_type.aggregation_source() != AggregationSource::External {
    bar_type = BarType::new(bar_type.instrument_id(), bar_type.aggregation(), bar_type.step(), bar_type.price_type(), AggregationSource::External);
}

Type guard

fn is_external(b: &BarType) -> bool {
    b.aggregation_source() == AggregationSource::External
}

Try / catch

match client.request_bars(bar_type, start, end, limit).await {
    Ok(bars) => bars,
    Err(e) if e.to_string().contains("Only EXTERNAL") => {
        // fall back to subscribing to external bar data over websocket
        Vec::new()
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling request_bars with a BarType created via BarType::new with AggregationSource::Internal (the default for internal aggregators), e.g. BTC-PERPETUAL*1-MINUTE*INTERNAL.

Common situations: Registering a data request with the internal aggregation source in a strategy config; copying BarType specs from a system where the internal aggregator synthesizes bars; confusion between live internal aggregation and historical external requests.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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