BloopAI/vibe-kanban · error

Failed to cleanly kill running execution processes

Error message

Failed to cleanly kill running execution processes

What it means

When the server shuts down gracefully, `perform_cleanup_actions` kills all execution processes tracked by the container service. `kill_all_running_processes()` returns a Result and the `.expect(...)` panics if any kill fails. The comment's promise of a 'graceful' shutdown is enforced here: any lingering execution that cannot be terminated crashes the cleanup path.

Source

Thrown at crates/server/src/startup.rs:191

    deployment
        .track_if_analytics_allowed("session_start", serde_json::json!({}))
        .await;

    // Preload global executor options cache for all executors with DEFAULT presets
    tokio::spawn(async move {
        executors::executors::utils::preload_global_executor_options_cache().await;
    });

    Ok(deployment)
}

/// Gracefully shut down running execution processes.
pub async fn perform_cleanup_actions(deployment: &DeploymentImpl) {
    deployment
        .container()
        .kill_all_running_processes()
        .await
        .expect("Failed to cleanly kill running execution processes");
}

const LEGACY_ATTACHMENT_MIGRATION_MARKER: &str = ".attachment-directories-migrated-v1";

#[derive(Default)]
struct DirectoryMigrationStats {
    moved_files: u64,
    removed_duplicates: u64,
    created_directories: u64,
    failures: u64,
}

impl DirectoryMigrationStats {
    fn merge(&mut self, other: DirectoryMigrationStats) {
        self.moved_files += other.moved_files;
        self.removed_duplicates += other.removed_duplicates;
        self.created_directories += other.created_directories;
        self.failures += other.failures;

View on GitHub (pinned to 4deb7eca8f)

Solutions

  1. Inspect the underlying error from kill_all_running_processes to see which execution/process failed and why
  2. Retrying the kill or sending SIGKILL after a graceful-signal timeout usually clears lingering processes
  3. Treat kill failures as non-fatal at shutdown: log the error instead of panicking, since the process is exiting anyway
  4. Ensure executors track process handles (Child::id etc.) and reap exited children so kills target live PIDs
  5. Add a cleanup timeout so a stuck kill cannot hang shutdown

Example fix

// before
deployment.container().kill_all_running_processes().await
    .expect("Failed to cleanly kill running execution processes");
// after
if let Err(e) = deployment.container().kill_all_running_processes().await {
    tracing::error!("Failed to kill running execution processes during shutdown: {}", e);
}
Defensive patterns

Strategy: try-catch

Try / catch

// Catch the cleanup panic at the shutdown boundary:
let handle = tokio::spawn(async move { perform_cleanup_actions(&deployment).await });
if let Err(join_err) = handle.await {
    tracing::error!("cleanup panicked: {}", join_err); // don't crash shutdown
}
// Preferred: replace expect with logged error inside perform_cleanup_actions

Prevention

When it happens

Trigger: Calling `serve()`'s shutdown path (or `perform_cleanup_actions` directly) while `container().kill_all_running_processes()` returns an Err — e.g. the underlying executor/process handles are stale, the process already exited with an unexpected state, or an internal error occurs while enumerating/killing tracked executions.

Common situations: Killing the app during an active task execution where child processes have already re-parented or become zombies; container/executors on remote deployments returning errors mid-kill; shutdown racing with an execution that just finished, producing a stale-handle error.

Related errors


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