nautechsystems/nautilus_trader · error

owner present

Error message

owner present

What it means

When claiming ownership of an unowned channel, the adapter looks up the owner in `self.owners` and sets its channel. This `expect("owner present")` fires if the owner key is missing from the map at that point — the function assumes the earlier lookup that produced `owned` already guaranteed the entry exists. Reaching the panic means internal state was mutated between the check and the insert, or a new owner was passed without being registered first.

Source

Thrown at crates/adapters/derive/src/data.rs:2040

            },
        );
        Some(generation)
    }

    fn attach_channel(&mut self, owner: ChannelOwner, generation: u64, channel: String) -> bool {
        let Some(owned) = self.owners.get(&owner) else {
            return false;
        };

        if owned.generation != generation {
            return false;
        }

        if let Some(active_channel) = &owned.channel {
            return active_channel == &channel;
        }

        self.owners.get_mut(&owner).expect("owner present").channel = Some(channel.clone());
        self.channels.entry(channel).or_default().insert(owner);
        true
    }

    fn is_current(&self, owner: ChannelOwner, generation: u64) -> bool {
        self.owners
            .get(&owner)
            .is_some_and(|owned| owned.generation == generation)
    }

    fn is_current_channel(&self, owner: ChannelOwner, generation: u64, channel: &str) -> bool {
        self.owners.get(&owner).is_some_and(|owned| {
            owned.generation == generation && owned.channel.as_deref() == Some(channel)
        })
    }

    fn remove_if_generation(
        &mut self,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure every owner passed to the claim function is inserted into `self.owners` (with its generation) before the channel-assignment branch.
  2. Use the entry API (`self.owners.entry(owner)`) so the insert and update are one atomic step instead of relying on the earlier check.
  3. If concurrency is possible, hold the borrow/mutex across the check and mutation.
  4. Add a debug_assert for owner presence with context about which owner was missing.

Example fix

// before
self.owners.get_mut(&owner).expect("owner present").channel = Some(channel.clone());
// after
if let Some(rec) = self.owners.get_mut(&owner) {
    rec.channel = Some(channel.clone());
} else {
    tracing::error!(?owner, "owner missing from registry at claim time");
    return false;
}
Defensive patterns

Strategy: validation

Validate before calling

debug_assert!(self.owners.contains_key(&owner), "owner {:?} must be registered before claiming", owner);
if !self.owners.contains_key(&owner) {
    tracing::error!(?owner, "owner missing from registry");
    return false;
}

Prevention

When it happens

Trigger: Calling the channel-claim function with a `ChannelOwner` that was never inserted into `self.owners` (e.g. a newly constructed owner value not present in the map), or concurrent mutation of `owners` invalidating the earlier existence check.

Common situations: Hit during adapter development when adding new ChannelOwner variants or subscription kinds and forgetting to insert them into the owners map in the earlier code path; also after refactors that change how `owned` is derived.

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