nautechsystems/nautilus_trader · error · anyhow::Error

external message bus factory cannot be combined with injecte

Error message

external message bus factory cannot be combined with injected egress

What it means

NautilusKernelBuilder::build refuses a configuration that sets both an external message bus factory and injected external msgbus egress. These are two alternative mechanisms for integrating an external message bus, and combining them is ambiguous, so the builder fails fast at build time. It is a configuration-conflict check, not a runtime fault.

Source

Thrown at crates/system/src/builder.rs:337

    /// Build and inject external message bus egress from a factory.
    #[must_use]
    pub fn with_external_msgbus_factory(
        mut self,
        factory: Box<dyn MessageBusBackingFactory>,
    ) -> Self {
        self.external_msgbus_factory = Some(factory);
        self
    }

    /// Build the [`NautilusKernel`] with the configured settings.
    ///
    /// # Errors
    ///
    /// Returns an error if kernel initialization fails.
    pub fn build(self) -> anyhow::Result<NautilusKernel> {
        if self.external_msgbus_factory.is_some() && self.external_msgbus_egress.is_some() {
            anyhow::bail!("external message bus factory cannot be combined with injected egress");
        }

        if self.external_msgbus_factory.is_some()
            && self
                .msgbus
                .as_ref()
                .and_then(|config| config.external_streams.as_ref())
                .is_some_and(|streams| !streams.is_empty())
        {
            anyhow::bail!(
                "NautilusKernelBuilder cannot consume external message bus streams; \
                 use LiveNodeBuilder::with_external_msgbus_factory for ingress"
            );
        }

        let config = KernelConfig {
            environment: self.environment,
            trader_id: self.trader_id,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Remove one of the two calls: keep the injected egress if you want direct message forwarding, or keep the factory if you want the external bus to be constructed by the factory
  2. Use LiveNodeBuilder::with_external_msgbus_factory instead if the external bus owns both ingress and egress
  3. Decide the integration style explicitly and set only the corresponding builder option

Example fix

// before
let kernel = NautilusKernelBuilder::new(config)
    .with_external_msgbus_factory(factory)
    .with_external_msgbus_egress(egress)
    .build()?;
// after
let kernel = NautilusKernelBuilder::new(config)
    .with_external_msgbus_egress(egress)
    .build()?;
Defensive patterns

Strategy: validation

Validate before calling

// Before build(): assert only one external-bus integration is configured
debug_assert!(
    !(cfg.external_msgbus_factory.is_some() && cfg.external_msgbus_egress.is_some()),
    "choose either external msgbus factory or injected egress, not both"
);

Try / catch

match builder.build() {
    Err(e) if e.to_string().contains("cannot be combined with injected egress") => {
        // strip one of the two options and rebuild
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling NautilusKernelBuilder::with_external_msgbus_factory(...) and also providing external_msgbus_egress(...) on the same builder, then calling build().

Common situations: Copy-pasting wiring code from a LiveNodeBuilder example (which uses the factory) into a kernel builder that already injects egress; refactoring the bus integration and leaving both hooks set.

Related errors


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