tracel-ai/burn · error

Autobatcher should be able to send resulting actions.

Error message

Autobatcher should be able to send resulting actions.

What it means

flush_actions sends each batched action back to its waiting agent via a oneshot sender and expects delivery to succeed. Panic means a receiver was already dropped — the agent went away before the policy flushed the batch.

Source

Thrown at crates/burn-rl/src/policy/async_policy.rs:96

        let input: Vec<_> = self
            .batch_action
            .iter()
            .map(|m| m.inference_state.clone())
            .collect();
        // Only deterministic if all actions are requested as deterministic.
        let deterministic = self.batch_action.iter().all(|item| item.deterministic);
        let (actions, context) = self
            .inner_policy
            .action(P::Observation::batch(input), deterministic);
        let actions: Vec<_> = actions.unbatch();

        for (i, item) in self.batch_action.iter().enumerate() {
            item.sender
                .send(ActionContext {
                    context: vec![context[i].clone()],
                    action: actions[i].clone(),
                })
                .expect("Autobatcher should be able to send resulting actions.");
        }
        self.batch_action.clear();
    }

    pub fn flush_logits(&mut self) {
        if self.len_logits() == 0 {
            return;
        }
        let input: Vec<_> = self
            .batch_logits
            .iter()
            .map(|m| m.inference_state.clone())
            .collect();
        let output = self.inner_policy.forward(P::Observation::batch(input));
        let logits: Vec<_> = output.unbatch();
        for (i, item) in self.batch_logits.iter().enumerate() {
            item.sender
                .send(logits[i].clone())

View on GitHub (pinned to d16f7ba2ed)

Solutions

  1. Ensure agents stay alive until flush_actions completes — don't drop their receivers mid-batch
  2. Drain/flush pending actions before decrementing agents or updating the policy
  3. Make agent shutdown cooperative: let it consume its action before terminating
  4. Replace expect with error handling to skip dead receivers instead of panicking

Example fix

// before
item.sender.send(ActionContext { ... })
    .expect("Autobatcher should be able to send resulting actions.");
// after
if item.sender.send(ActionContext { ... }).is_err() {
    // receiver dropped; skip this agent
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Before update_policy, confirm all batched agents still hold receivers
assert_eq!(self.batch_action.iter().filter(|i| i.sender.is_closed()).count(), 0,
    "some agents dropped before flush_actions");

Try / catch

if let Err(e) = item.sender.send(ActionContext { context: vec![context[i].clone()], action: actions[i].clone() }) {
    log::warn!("agent receiver dropped, skipping: {e}");
    continue;
}

Prevention

When it happens

Trigger: An agent thread/context is dropped (decremented/aborted) after push_action queued its sender but before update_policy's flush_actions runs; then send() fails on the dead receiver.

Common situations: Aborting agent tasks mid-episode; panics in agent code dropping its receiver; calling decrement_agents while batched actions are still pending; race between policy update and agent teardown.

Related errors


AI-assisted analysis of tracel-ai/burn@d16f7ba2ed (2026-09-05). Data as JSON: /api/errors/a22e7118f6076e51. Report an issue: GitHub.