nautechsystems/nautilus_trader · error · anyhow::Error

Only EXTERNAL aggregation is supported

Error message

Only EXTERNAL aggregation is supported

What it means

Hyperliquid bars must be requested with EXTERNAL aggregation source: the adapter fetches pre-aggregated candles from the exchange HTTP API rather than aggregating ticks internally. bar_type_to_interval throws this error when a bar type with any other aggregation source (e.g. INTERNAL) is passed to request_bars, subscribe_bars, or unsubscribe_bars.

Source

Thrown at crates/adapters/hyperliquid/src/common/parse.rs:441

                }
            } else {
                // No market price available, default to SL for safety
                HyperliquidExchangeTpSl::Sl
            }
        }
    }
}

/// Converts a Nautilus `BarType` to a Hyperliquid bar interval.
///
/// # Errors
///
/// Returns an error if the bar type uses an unsupported aggregation or step value.
pub fn bar_type_to_interval(bar_type: &BarType) -> anyhow::Result<HyperliquidBarInterval> {
    let spec = bar_type.spec();
    let step = spec.step.get();

    anyhow::ensure!(
        bar_type.aggregation_source() == AggregationSource::External,
        "Only EXTERNAL aggregation is supported"
    );

    let interval = match spec.aggregation {
        BarAggregation::Minute => match step {
            1 => OneMinute,
            3 => ThreeMinutes,
            5 => FiveMinutes,
            15 => FifteenMinutes,
            30 => ThirtyMinutes,
            _ => anyhow::bail!("Unsupported minute step: {step}"),
        },
        BarAggregation::Hour => match step {
            1 => OneHour,
            2 => TwoHours,
            4 => FourHours,
            8 => EightHours,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Construct the BarType with AggregationSource::External (e.g. use 'BTC-PERP.HYPERLIQUID-1-MINUTE.EXTERNAL' style bar type strings)
  2. Set the strategy/config to use external aggregation for Hyperliquid data subscriptions
  3. If internal aggregation is required, use an aggregating data engine/adapter that supports it instead of the Hyperliquid adapter directly
  4. Validate bar types at startup against bar_type.aggregation_source() before subscribing

Example fix

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

Strategy: validation

Validate before calling

if bar_type.aggregation_source() != AggregationSource::External {
    return Err(anyhow!("Hyperliquid requires EXTERNAL aggregation, got {:?}", bar_type.aggregation_source()));
}
client.request_bars(bar_type)?;

Type guard

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

Try / catch

match bar_type_to_interval(&bar_type) {
    Err(e) if e.to_string().contains("Only EXTERNAL aggregation") => {
        eprintln!("Rebuild bar_type with AggregationSource::External");
    }
    Err(e) => return Err(e),
    Ok(interval) => subscribe(interval),
}

Prevention

When it happens

Trigger: Calling request_bars/subscribe_bars with a BarType whose aggregation_source is not AggregationSource::External — e.g. a bar type built with INTERNAL aggregation or with the wrong aggregation source specifier in the bar type string.

Common situations: Configuring strategy subscriptions with INTERNAL bar aggregation while using the Hyperliquid data client; copying bar-type strings from adapters that support internal aggregation; defaulting bar aggregation source in config without specifying External.

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/a0057512a913c4d5. Report an issue: GitHub.