nautechsystems/nautilus_trader · error · anyhow::Error

Correlation ID <{correlation_id}> already has a registered h

Error message

Correlation ID <{correlation_id}> already has a registered handler

What it means

register_response_handler maps a correlation ID (UUID4) to exactly one handler in correlation_index. Registering a second handler for the same correlation ID is ambiguous (which handler gets the response?) so the bus rejects it with this error before mutating the index.

Source

Thrown at crates/common/src/msgbus/core.rs:822

                buf.push(sub.handler.clone());
            }

            self.topics.insert(topic, matches);
        }
    }

    /// Registers a response handler for a specific correlation ID.
    ///
    /// # Errors
    ///
    /// Returns an error if `handler` is already registered for the `correlation_id`.
    pub fn register_response_handler(
        &mut self,
        correlation_id: &UUID4,
        handler: ShareableMessageHandler,
    ) -> anyhow::Result<()> {
        if self.correlation_index.contains_key(correlation_id) {
            anyhow::bail!("Correlation ID <{correlation_id}> already has a registered handler");
        }

        self.correlation_index.insert(*correlation_id, handler);

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use std::{
        any::Any,
        cell::RefCell,
        collections::hash_map::DefaultHasher,
        fmt::Debug,
        hash::{Hash, Hasher},
        rc::Rc,
    };

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Generate a fresh UUID4 correlation ID for each new request instead of reusing one.
  2. Check `correlation_index.contains_key` (or attempt the register) and skip/error cleanly when already registered.
  3. If re-registration is intentional, add an unregister/deregister step for the old handler before registering the new one, if such an API exists.
  4. In retry logic, keep the original handler registered and only send the retry message — do not re-register.

Example fix

// before
bus.register_response_handler(&corr_id, handler.clone())?; // bails if exists
// after
let corr_id = UUID4::new(); // unique per request
bus.register_response_handler(&corr_id, handler)?;
Defensive patterns

Strategy: validation

Validate before calling

// ensure a fresh correlation id per registration
let corr_id = UUID4::new();
assert_ne!(corr_id, previous_corr_id);

Try / catch

if let Err(e) = bus.register_response_handler(&corr_id, handler) {
    if e.to_string().contains("already has a registered handler") {
        // reuse existing registration instead of failing
    } else {
        return Err(e);
    }
}

Prevention

When it happens

Trigger: Calling MessageBusCore::register_response_handler with a correlation_id that already has an entry — e.g. re-subscribing with a reused correlation ID, or a retry that re-registers instead of reusing the original registration.

Common situations: Request/retry logic that regenerates registrations without checking existence; replaying recorded sessions where correlation IDs repeat; a client reconnect path that re-registers handlers for in-flight request IDs.

Related errors


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