nautechsystems/nautilus_trader · warning

Polymarket RTDS task owner was dropped

Error message

Polymarket RTDS task owner was dropped

What it means

Raised during RTDS shutdown/teardown when the task-slot owner has already been dropped, so retained tasks cannot be finalized. The code clears the reset-live-state flag, notifies reconcilers, then bails because there is no task owner left to shut down. It signals a double shutdown or shutdown of an already-torn-down feed.

Source

Thrown at crates/adapters/polymarket/src/rtds.rs:646

        }

        self.inner.reconcile_pending.store(true, Ordering::Release);
        self.ensure_reconcile_worker();
        self.inner.reconcile_notify.notify_one();
    }

    pub(crate) async fn disconnect(&self) -> anyhow::Result<()> {
        self.begin_shutdown();
        let _guard = self.inner.wire_mutex.lock().await;

        self.inner.reconcile_pending.store(false, Ordering::Release);
        self.inner
            .reset_live_state_pending
            .store(false, Ordering::Release);
        self.inner.reconcile_notify.notify_waiters();

        let Some(tasks) = self.task_slots() else {
            anyhow::bail!("Polymarket RTDS task owner was dropped");
        };
        let mut ws = RtdsWebSocketGuard::take(&self.inner.ws_client);

        if let Some(client) = ws.ws.as_ref() {
            client.disconnect().await;
        }

        if let Some(control) = &self.inner.socket_control {
            control.deregister();
        }

        self.inner.live_subscriptions.lock().clear();
        drop(_guard);

        let mut message_slot = tasks.message.lock().await;
        if let Some(outcome) = finish_task(
            &mut message_slot,
            Duration::from_secs(2),

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Make shutdown idempotent: check whether task slots still exist before calling close.
  2. Serialize shutdown calls (single closer task, JoinHandle, or a OnceLock-style flag).
  3. Treat this error as 'already shut down' and ignore it in close paths.
  4. Ensure exactly one component owns and closes the feed.

Example fix

// before
feed.close().await?; // second call bails
feed.close().await?;
// after
if !feed.is_closed() {
    feed.close().await?;
}
Defensive patterns

Strategy: try-catch

Validate before calling

if feed.is_closed() {
    return Ok(()); // already shut down
}

Type guard

fn needs_shutdown(feed: &PolymarketRtdsFeed) -> bool {
    !feed.is_closed() && feed.task_slots().is_some()
}

Try / catch

if let Err(e) = feed.close().await {
    if e.to_string().contains("task owner was dropped") {
        log::debug!("already shut down");
    } else {
        return Err(e);
    }
}

Prevention

When it happens

Trigger: Calling close/shutdown on the Polymarket RTDS feed when the RtdsTaskSlots owner was already dropped — a second close call, or close racing a completed teardown from another task.

Common situations: Calling disconnect/shutdown twice (e.g. from both a Drop impl and an explicit shutdown path); engine teardown invoking close on a feed whose supervisor already exited.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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