charmbracelet/crush · error

error starting shell: %w

Error message

error starting shell: %w

What it means

For foreground execution the tool also spawns the command through the background shell manager with a detached context (so it can be auto-backgrounded on timeout). If bgManager.Start fails to spawn the process, the tool returns 'error starting shell' wrapping the cause.

Source

Thrown at internal/agent/tools/bash.go:311

					EndTime:          time.Now().UnixMilli(),
					Description:      params.Description,
					WorkingDirectory: bgShell.WorkingDir,
					Background:       true,
					ShellID:          bgShell.ID,
				}
				response := fmt.Sprintf("Background shell started with ID: %s\n\nUse job_output tool to view output or job_kill to terminate.", bgShell.ID)
				return fantasy.WithResponseMetadata(fantasy.NewTextResponse(response), metadata), nil
			}

			// Start synchronous execution with auto-background support
			startTime := time.Now()

			// Start with detached context so it can survive if moved to background
			bgManager := shell.GetBackgroundShellManager()
			bgManager.Cleanup()
			bgShell, err := bgManager.Start(context.Background(), execWorkingDir, blockFuncs(), params.Command, params.Description)
			if err != nil {
				return fantasy.ToolResponse{}, fmt.Errorf("error starting shell: %w", err)
			}

			// Wait for either completion, auto-background threshold, or context cancellation
			ticker := time.NewTicker(100 * time.Millisecond)
			defer ticker.Stop()

			autoBackgroundAfter := cmp.Or(params.AutoBackgroundAfter, DefaultAutoBackgroundAfter)
			autoBackgroundThreshold := time.Duration(autoBackgroundAfter) * time.Second
			timeout := time.After(autoBackgroundThreshold)

			var stdout, stderr string
			var done bool
			var execErr error

		waitLoop:
			for {
				select {
				case <-ticker.C:

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Confirm the working directory (params.WorkingDir or tool default) exists and is accessible
  2. Check the wrapped cause for the exact OS error and address it (PATH, permissions, disk, ulimit)
  3. Ensure the environment allows spawning processes (sandbox/container policy, fd/PID limits)
  4. Retry after fixing environment; if the manager stays broken, restart the application

Example fix

// before
Bash(command="make", working_dir="/deleted/build")
// after
Bash(command="make", working_dir="/repo/build")
Defensive patterns

Strategy: validation

Validate before calling

wd := cmp.Or(params.WorkingDir, defaultDir)
if info, err := os.Stat(wd); err != nil || !info.IsDir() {
    return fmt.Errorf("invalid working dir %q", wd)
}
if _, err := exec.LookPath("sh"); err != nil {
    return fmt.Errorf("no shell on PATH")
}

Try / catch

bgShell, err := bgManager.Start(ctx, wd, blockers, cmd, desc)
if err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) { /* fix path/permissions */ }
    return fmt.Errorf("cannot start shell: %w", err)
}

Prevention

When it happens

Trigger: Synchronous bash call where the working directory is invalid or inaccessible, the shell executable is unavailable, fork/exec is blocked by sandbox/limits, or the background manager's internal Start errors — the process never launches at all.

Common situations: params.WorkingDir points to a deleted directory; running inside restricted containers (no /bin/sh, seccomp denying fork); resource exhaustion (PID/fd limits) from prior leaked shells; permissions changed on the working dir.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/d406a0d44a060cf3. Report an issue: GitHub.