tinyhumansai/openhuman · error

CapturingObserver steps mutex poisoned

Error message

CapturingObserver steps mutex poisoned

What it means

Mutex poisoning on CapturingObserver's steps mutex in the flows dry-run tooling: the observer collects ExecutionStep records (including null-resolution diagnostics) during the sandbox run; if a panic unwound while that mutex was held, later lock() calls in DryRunWorkflowTool's inspection path hit PoisonError and this expect fires. The dry-run result is lost; the originating panic is the real fault.

Source

Thrown at src/openhuman/flows/builder_tools.rs:3463

/// node's [`ExecutionStep`](tinyflows::observability::ExecutionStep) — in
/// particular its `diagnostics` (null-resolved `=`-expressions the engine
/// traced during that node's config resolution) — so [`DryRunWorkflowTool`]
/// can inspect them once the sandbox run settles. See the struct's "Null-
/// resolution check" doc for why this exists.
/// `pub(crate)` (not private) so [`crate::openhuman::flows::ops::validate_required_arg_resolvability`]
/// (issue B18 — escalating a null-resolved REQUIRED outbound arg to a hard
/// authoring-time reject) can run the identical sandbox-capture shape without
/// duplicating this struct.
#[derive(Default)]
pub(crate) struct CapturingObserver {
    steps: std::sync::Mutex<Vec<tinyflows::observability::ExecutionStep>>,
}

impl tinyflows::observability::RunObserver for CapturingObserver {
    fn on_step_finish(&self, step: &tinyflows::observability::ExecutionStep) {
        self.steps
            .lock()
            .expect("CapturingObserver steps mutex poisoned")
            .push(step.clone());
    }
}

impl CapturingObserver {
    /// A snapshot of every step recorded so far (steps are pushed
    /// synchronously from `on_step_finish`, so once the run's future resolves
    /// every step it will ever record is already present).
    pub(crate) fn steps(&self) -> Vec<tinyflows::observability::ExecutionStep> {
        self.steps
            .lock()
            .expect("CapturingObserver steps mutex poisoned")
            .clone()
    }
}

// ─────────────────────────────────────────────────────────────────────────────
// save_workflow — persist a built graph onto an EXISTING saved flow

View on GitHub (pinned to 7491200858)

Solutions

  1. Fix the panic that occurred mid-capture (visible earlier in the run log)
  2. Scope the steps lock to the shortest possible region so engine panics cannot hold it
  3. Recover with into_inner() if partial captured steps are still useful for diagnostics
Defensive patterns

Strategy: try-catch

When it happens

Trigger: Thrown at src/openhuman/flows/builder_tools.rs:3463 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/21280cdb7a666845. Report an issue: GitHub.