{"record":{"id":"63b413efe98671c1","repo":"charmbracelet/crush","slug":"directory-does-not-exist-w","errorCode":null,"errorMessage":"directory does not exist: %w","messagePattern":"directory does not exist: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/shell/shell.go","lineNumber":148,"sourceCode":"\n\treturn s.execStream(ctx, command, stdout, stderr)\n}\n\n// GetWorkingDir returns the current working directory\nfunc (s *Shell) GetWorkingDir() string {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\treturn s.cwd\n}\n\n// SetWorkingDir sets the working directory\nfunc (s *Shell) SetWorkingDir(dir string) error {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\n\t// Verify the directory exists\n\tif _, err := os.Stat(dir); err != nil {\n\t\treturn fmt.Errorf(\"directory does not exist: %w\", err)\n\t}\n\n\ts.cwd = dir\n\treturn nil\n}\n\n// GetEnv returns a copy of the environment variables\nfunc (s *Shell) GetEnv() []string {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\n\tenv := make([]string, len(s.env))\n\tcopy(env, s.env)\n\treturn env\n}\n\n// SetEnv sets an environment variable\nfunc (s *Shell) SetEnv(key, value string) {","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/shell/shell.go#L130-L166","documentation":"Shell.SetWorkingDir in internal/shell/shell.go verifies the target directory with os.Stat before switching the shell's working directory. If Stat fails (missing path, permission problem, or path is a file), the raw error is wrapped as \"directory does not exist: %w\" and the cwd is left unchanged. The shell state is protected under a mutex, so the error is atomic.","triggerScenarios":"Calling SetWorkingDir(\"/path/that/does/not/exist\"), calling it with a file path instead of a directory, or with a path the process lacks search permission on. Any os.Stat error (including permission) yields this message.","commonSituations":"Restoring a session whose previous cwd was deleted; pointing the shell at a worktree or temp dir that was cleaned up; typo in path; using a path inside a container that was never mounted.","solutions":["Create the directory first (os.MkdirAll) before calling SetWorkingDir.","Verify the path is a directory, not a file, and fix the caller.","Check permissions on the path and its parents.","Re-check the stored path for staleness (deleted temp/worktree dirs) and resolve to an existing directory."],"exampleFix":"// before\nshell.SetWorkingDir(\"/tmp/build-123\") // may not exist\n// after\nos.MkdirAll(\"/tmp/build-123\", 0o755)\nshell.SetWorkingDir(\"/tmp/build-123\")","handlingStrategy":"validation","validationCode":"func dirExists(p string) bool {\n\tinfo, err := os.Stat(p)\n\treturn err == nil && info.IsDir()\n}\nif !dirExists(dir) { os.MkdirAll(dir, 0o755) }\nerr := sh.SetWorkingDir(dir)","typeGuard":null,"tryCatchPattern":"if err := sh.SetWorkingDir(dir); err != nil {\n\tvar pe *fs.PathError\n\tif errors.As(err, &pe) && errors.Is(pe.Err, fs.ErrNotExist) {\n\t\tos.MkdirAll(dir, 0o755)\n\t\terr = sh.SetWorkingDir(dir)\n\t}\n}","preventionTips":["Always os.MkdirAll the target before SetWorkingDir.","Check info.IsDir() to catch file-instead-of-directory mistakes.","Validate persisted cwd paths when restoring sessions — they may be stale.","Use absolute paths to avoid dependency on the process cwd."],"tags":["filesystem","working-directory","validation"],"backgroundTag":"directory-not-found","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}