BloopAI/vibe-kanban · error · ContainerError

MsgStore not found for execution

Error message

MsgStore not found for execution

What it means

track_child_msgs_in_store looks up the in-memory MsgStore registered for the execution id and errors if none is registered. The store must exist because stdout/stderr streams are piped into it as LogMsg values. This is an internal lifecycle race: the child process exists but its message store was removed or never registered.

Source

Thrown at crates/local-deployment/src/container.rs:865

            }
        });
        rx
    }

    fn dir_name_from_workspace(workspace_id: &Uuid, task_title: &str) -> String {
        let task_title_id = git_branch_id(task_title);
        format!("{}-{}", short_uuid(workspace_id), task_title_id)
    }

    async fn track_child_msgs_in_store(
        &self,
        id: Uuid,
        child: &mut AsyncGroupChild,
    ) -> Result<(), ContainerError> {
        let store = self
            .get_msg_store_by_id(&id)
            .await
            .ok_or_else(|| ContainerError::Other(anyhow!("MsgStore not found for execution")))?;
        let out = child.inner().stdout.take().expect("no stdout");
        let err = child.inner().stderr.take().expect("no stderr");

        // Map stdout bytes -> LogMsg::Stdout
        let out = ReaderStream::new(out)
            .map_ok(|chunk| LogMsg::Stdout(String::from_utf8_lossy(&chunk).into_owned()));

        // Map stderr bytes -> LogMsg::Stderr
        let err = ReaderStream::new(err)
            .map_ok(|chunk| LogMsg::Stderr(String::from_utf8_lossy(&chunk).into_owned()));

        // If you have a JSON Patch source, map it to LogMsg::JsonPatch too, then select all three.

        // Merge and forward into the store
        let merged = select(out, err); // Stream<Item = Result<LogMsg, io::Error>>
        store.clone().spawn_forwarder(merged);
        Ok(())
    }

View on GitHub (pinned to 4deb7eca8f)

Solutions

  1. Retry the execution — the race is usually transient.
  2. Ensure the MsgStore is registered for the execution id before spawning the child process.
  3. Check that stop/cancel paths only remove the store after the child is fully torn down.
  4. If reproducible, capture logs and report; it indicates a lifecycle-ordering bug in the execution manager.

Example fix

// before
let spawned = executor_action.spawn(...).await??;
self.track_child_msgs_in_store(id, &mut spawned.child).await?;
// after
self.ensure_msg_store(id).await; // register store first
let spawned = executor_action.spawn(...).await??;
self.track_child_msgs_in_store(id, &mut spawned.child).await?;
Defensive patterns

Strategy: retry

Validate before calling

// before spawning, confirm the store is registered
if container.get_msg_store_by_id(&id).await.is_none() {
    container.register_msg_store(&id);
}

Try / catch

match container.start_execution(...).await {
    Err(ContainerError::Other(e)) if e.to_string().contains("MsgStore not found") => {
        // transient race — retry once after re-registering the store
        container.register_msg_store(&id);
        container.start_execution(...).await
    }
    other => other,
}

Prevention

When it happens

Trigger: start_execution_inner spawning a child whose execution_process id has no MsgStore in the container's store map — e.g. store cleaned up concurrently, execution was cancelled, or the store was never inserted before spawn.

Common situations: Rapid stop/cancel of an execution racing with its startup; kill_all_running_processes clearing stores mid-spawn; internal bug where register/deregister ordering is wrong under load.

Related errors


AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29). Data as JSON: /api/errors/b7b46740eee115c9. Report an issue: GitHub.