nautechsystems/nautilus_trader · error

RequestJoin must be handled by handle_request_join

Error message

RequestJoin must be handled by handle_request_join

What it means

RequestCommand::Join requests are not processed by the generic request dispatch path; they have a dedicated handle_request_join method. Reaching the generic match arm with a Join request indicates an internal routing invariant was violated, so the engine bails.

Source

Thrown at crates/data/src/engine/mod.rs:1384

        };
        let resolved_client_id = client.client_id();

        match req {
            RequestCommand::Data(req) => client.request_data(req),
            RequestCommand::Instrument(req) => client.request_instrument(req),
            RequestCommand::Instruments(req) => client.request_instruments(req),
            RequestCommand::BookSnapshot(req) => client.request_book_snapshot(req),
            RequestCommand::BookDeltas(req) => client.request_book_deltas(req),
            RequestCommand::BookDepth(req) => client.request_book_depth(req),
            RequestCommand::Quotes(req) => client.request_quotes(req),
            RequestCommand::Trades(req) => client.request_trades(req),
            RequestCommand::FundingRates(req) => client.request_funding_rates(req),
            RequestCommand::OptionChainReferencePrice(req) => {
                client.request_option_chain_reference_price(req)
            }
            RequestCommand::Bars(req) => client.request_bars(req),
            RequestCommand::Join(_) => {
                anyhow::bail!("RequestJoin must be handled by handle_request_join")
            }
        }?;

        Ok(resolved_client_id)
    }

    fn execute_continuous_future_request(&mut self, req: RequestCommand) -> anyhow::Result<()> {
        let RequestCommand::Bars(parent) = req else {
            anyhow::bail!("Continuous future requests require `RequestBars`");
        };
        let request_id = parent.request_id;
        let Some(continuous_request) = continuous_future_request_from_bars(&parent)? else {
            return Ok(());
        };

        self.ensure_continuous_future_target_instrument(&continuous_request);
        self.prepare_request_bar_aggregators_from_state(
            request_id,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Route RequestCommand::Join through DataEngine.handle_request_join instead of request/execute_request
  2. In generic dispatch code, match RequestCommand::Join first and delegate to handle_request_join
  3. Check the library version's API: join requests have a dedicated entry point, not the generic one
  4. If this arises without custom routing code, report it as an internal invariant bug

Example fix

// before
engine.request(RequestCommand::Join(join_req));
// after
engine.handle_request_join(join_req);
Defensive patterns

Strategy: validation

Validate before calling

if let RequestCommand::Join(join) = &cmd {
    engine.handle_request_join(join.clone());
    return Ok(());
}
engine.request(cmd);

Type guard

fn is_join(cmd: &RequestCommand) -> Option<&RequestJoin> {
    match cmd { RequestCommand::Join(j) => Some(j), _ => None }
}

Try / catch

match engine.request(cmd) {
    Err(e) if e.to_string().contains("handle_request_join") => {
        // reroute via handle_request_join
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling DataEngine.request (execute_request) with a RequestCommand::Join payload instead of calling handle_request_join; a code path that funnels all RequestCommand variants through the generic dispatcher.

Common situations: Custom integration or subclass code that wraps engine.request for every command type; refactors that removed the special-case routing for join requests; passing a join request into a generic batch-request helper.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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