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
- Confirm the working directory (params.WorkingDir or tool default) exists and is accessible
- Check the wrapped cause for the exact OS error and address it (PATH, permissions, disk, ulimit)
- Ensure the environment allows spawning processes (sandbox/container policy, fd/PID limits)
- 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
- Pass only existing, accessible directories as WorkingDir
- Verify container/sandbox permits process spawning
- Watch for fd/PID exhaustion when many commands run concurrently; clean up finished shells
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
- empty command
- session ID is required for executing shell command
- error starting background shell: %w
- [Job %s] error executing command: %w
- failed to start crush server: %v
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/d406a0d44a060cf3.
Report an issue: GitHub.