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
- Generate a fresh UUID4 correlation ID for each new request instead of reusing one.
- Check `correlation_index.contains_key` (or attempt the register) and skip/error cleanly when already registered.
- If re-registration is intentional, add an unregister/deregister step for the old handler before registering the new one, if such an API exists.
- 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
- Generate a new UUID4 correlation ID per request; never reuse IDs.
- In retry logic, keep the original handler; only resend the message.
- Centralize correlation ID creation in one factory function.
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
- external ingress receiver unavailable
- Order {primary_id} already being executed
- OrderList denied: duplicate {}
- Order in list denied: duplicate {}
- Invalid config type for AxExecutionClientFactory. Expected A
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/2220324e25500bad.
Report an issue: GitHub.