nautechsystems/nautilus_trader · error · anyhow::Error

Cannot resolve PERM-{target_perm_id}: matching open order ha

Error message

Cannot resolve PERM-{target_perm_id}: matching open order has no IB order_id

What it means

During perm_id lookup, a matching open order was found whose IB order_id is 0 (unassigned). IB uses order_id 0 for orders not originating from this API client (e.g. placed manually in TWS), so the perm_id cannot be mapped back to an API order_id and this error bails.

Source

Thrown at crates/adapters/interactive_brokers/src/execution/core.rs:2245

        while let Some(order_result) = subscription.next().await {
            let Orders::OrderData(data) = order_result? else {
                continue;
            };

            if !Self::is_active_open_order(&data.order) {
                continue;
            }

            if !data.order.account.is_empty() && data.order.account != raw_account_id {
                continue;
            }

            if data.order.perm_id != target_perm_id {
                continue;
            }

            if data.order_id == 0 {
                anyhow::bail!(
                    "Cannot resolve PERM-{target_perm_id}: matching open order has no IB order_id"
                );
            }

            return Ok(data.order_id);
        }

        anyhow::bail!("Cannot resolve PERM-{target_perm_id}: no matching open order found")
    }

    fn is_active_open_order(order: &ibapi::orders::Order) -> bool {
        !order.deactivate
    }

    fn is_definitive_order_submit_error(error: &ibapi::Error) -> bool {
        matches!(
            error,
            ibapi::Error::InvalidArgument(_) | ibapi::Error::ServerVersion(_, _, _)

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Place orders through the same API client that is performing the lookup
  2. Re-request open orders after IB assigns an order_id, or use reqOpenOrders for the owning client to trigger assignment
  3. Match orders by perm_id directly instead of requiring an API order_id
  4. Verify you are resolving the correct perm_id (not one belonging to a manual order)
Defensive patterns

Strategy: fallback

Validate before calling

// after finding data.order.perm_id == target_perm_id, check availability first
if data.order_id == 0 { /* cannot map via API order_id; use perm_id-based handling */ }

Type guard

fn has_api_order_id(data: &OrderData) -> Option<i32> {
    (data.order_id != 0).then_some(data.order_id)
}

Try / catch

match resolve_perm_id(perm_id).await {
    Ok(order_id) => order_id,
    Err(e) if e.to_string().contains("has no IB order_id") => {
        info!("PERM-{perm_id} is a non-API order; matching by perm_id only");
        fall_back_to_perm_id_matching(perm_id)
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: An order placed outside this API session (manual in TWS, or from a different client) has a perm_id equal to the target, but data.order_id == 0 in the open-orders snapshot.

Common situations: Reconciling orders placed manually or by another automation session; adapter restarted with a new client_id so IB returns unassigned order_ids; resolving a perm_id that belongs to a non-API order.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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