nautechsystems/nautilus_trader · error

Only EXTERNAL aggregation is supported

Error message

Only EXTERNAL aggregation is supported

What it means

Thrown by BinanceFuturesHttpClient::request_binance_bars when the BarType's aggregation_source is not AggregationSource::External. The method fetches venue-native klines, which only makes sense for externally-aggregated bars; internally-aggregated bar types are built by the local NautilusTrader aggregation engine from ticks, so requesting them from the venue is a category error the client rejects immediately.

Source

Thrown at crates/adapters/binance/src/futures/http/client.rs:2975

                )
            })
            .collect()
    }

    /// Requests bar (kline/candlestick) data for an instrument.
    ///
    /// # Errors
    ///
    /// Returns an error if the bar type is not supported, instrument is not cached,
    /// or the request fails.
    pub async fn request_binance_bars(
        &self,
        bar_type: BarType,
        start: Option<Timestamp>,
        end: Option<Timestamp>,
        limit: Option<u32>,
    ) -> anyhow::Result<Vec<BinanceBar>> {
        anyhow::ensure!(
            bar_type.aggregation_source() == AggregationSource::External,
            "Only EXTERNAL aggregation is supported"
        );

        let spec = bar_type.spec();
        let step = spec.step.get();
        let interval = match spec.aggregation {
            BarAggregation::Second => {
                anyhow::bail!("Binance Futures does not support second-level kline intervals")
            }
            BarAggregation::Minute => format!("{step}m"),
            BarAggregation::Hour => format!("{step}h"),
            BarAggregation::Day => format!("{step}d"),
            BarAggregation::Week => format!("{step}w"),
            BarAggregation::Month => format!("{step}M"),
            a => anyhow::bail!("Binance Futures does not support {a:?} aggregation"),
        };

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Use an External aggregation source in the BarType for venue kline requests (e.g. '...-1-MINUTE-LAST-EXTERNAL')
  2. For internal aggregation, instead request the underlying historical ticks/bars and let the internal aggregator build the bars
  3. Validate bar_type.aggregation_source() before dispatching to request_binance_bars

Example fix

// before
let bar_type: BarType = "BTCUSDT.BINANCE_PERP-1-MINUTE-LAST-INTERNAL".parse()?;
let bars = client.request_binance_bars(bar_type, start, end, None).await?;

// after
let bar_type: BarType = "BTCUSDT.BINANCE_PERP-1-MINUTE-LAST-EXTERNAL".parse()?;
let bars = client.request_binance_bars(bar_type, start, end, None).await?;
Defensive patterns

Strategy: type-guard

Validate before calling

if bar_type.aggregation_source() != AggregationSource::External {
    anyhow::bail!("refusing venue request for {bar_type}: not EXTERNAL");
}

Type guard

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

Try / catch

Guard on aggregation_source before the call; on error, re-issue with an EXTERNAL bar type or redirect to the internal aggregation pipeline.

Prevention

When it happens

Trigger: Calling request_binance_bars with a BarType parsed from a string like 'BTCUSDT.BINANCE_PERP-1-MINUTE-LAST-INTERNAL'; building a BarType with AggregationSource::Internal via the standard From<CompositePriceType> helpers and passing it to the HTTP client; generic historical-data loaders that forward any subscribed bar type to the venue request path.

Common situations: Strategies that subscribe to internal bars (e.g. for tick- or volume-aggregated synthetic bars) but reuse the same request path for historical backfill; misparsed bar type strings where the aggregation source suffix is wrong; confusion between the DataEngine's internal aggregation subscription route and the venue's kline endpoint.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16). Data as JSON: /api/errors/3b42080722046af8. Report an issue: GitHub.