nautechsystems/nautilus_trader · error

Empty `payload` for `delete` '{key}'

Error message

Empty `payload` for `delete` '{key}'

What it means

delete_from_index removes a key's value from a set/hash index during a Redis pipeline delete. For set indexes a payload (the member value, e.g. the order or position id bytes) is required; if the caller passes None payload, this error fires. It is an internal invariant: index deletions must always carry the member to remove.

Source

Thrown at crates/infrastructure/src/redis/cache.rs:1082

        value.is_some()
    );

    match collection {
        INDEX => delete_from_index(pipe, key, value),
        ORDERS | POSITIONS | ACCOUNTS | ACTORS | STRATEGIES => {
            delete_string(pipe, key);
            Ok(())
        }
        _ => anyhow::bail!("Unsupported operation: `delete` for collection '{collection}'"),
    }
}

fn delete_from_index(
    pipe: &mut Pipeline,
    key: &str,
    value: Option<Vec<Bytes>>,
) -> anyhow::Result<()> {
    let value = value.ok_or_else(|| anyhow::anyhow!("Empty `payload` for `delete` '{key}'"))?;
    let index_key = get_index_key(key)?;

    match index_key {
        INDEX_ORDER_IDS
        | INDEX_ORDERS
        | INDEX_ORDERS_OPEN
        | INDEX_ORDERS_CLOSED
        | INDEX_ORDERS_EMULATED
        | INDEX_ORDERS_INFLIGHT
        | INDEX_POSITIONS
        | INDEX_POSITIONS_OPEN
        | INDEX_POSITIONS_CLOSED => {
            remove_from_set(pipe, key, value[0].as_ref());
            Ok(())
        }
        INDEX_ORDER_POSITION | INDEX_ORDER_CLIENT => {
            remove_from_hash(pipe, key, value[0].as_ref());
            Ok(())

View on GitHub (pinned to 18893faf8b)

Solutions

  1. If you call the cache delete API directly, always provide Some(vec![member_bytes]) as the payload when deleting from an index key.
  2. Check any custom adapter code that constructs DatabaseCommand objects for Delete operations and ensure payloads are set for index keys.
  3. Verify the key actually denotes an index; plain record deletes (orders/positions) use None payload legitimately and skip this path.
  4. Upgrade nautilus_trader if this arises from stock delete_order/delete_position — it would indicate an internal bug.

Example fix

// before
let op = DatabaseCommand::new(DatabaseOperation::Delete, index_key, None);
// after
let op = DatabaseCommand::new(DatabaseOperation::Delete, index_key, Some(vec![member_id_bytes.clone()]));
Defensive patterns

Strategy: validation

Validate before calling

// ensure index deletes always carry a payload
assert!(payload.is_some(), "index delete requires member payload");

Type guard

fn has_payload(p: &Option<Vec<Bytes>>) -> bool { p.as_ref().map_or(false, |v| !v.is_empty()) }

Prevention

When it happens

Trigger: A delete operation whose key maps to an index (INDEX_ORDER_IDS, INDEX_ORDERS, INDEX_ORDERS_OPEN, etc.) is issued without a payload — i.e. DatabaseCommand::new(Delete, index_key, None) reaches the pipeline builder.

Common situations: Usually triggered by internal code paths or custom integrations that build delete commands manually and omit the payload; not normally hit by end users through delete_order/delete_position, which always supply payloads.

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/8894a81e892457c4. Report an issue: GitHub.