{"record":{"id":"3c54cd48ceb637e2","repo":"wavetermdev/waveterm","slug":"error-statting-cwd-q-w","errorCode":null,"errorMessage":"error statting cwd %q: %w","messagePattern":"error statting cwd %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/shellexec/shellexec.go","lineNumber":115,"sourceCode":"func ExitCodeFromWaitErr(err error) int {\n\tif err == nil {\n\t\treturn 0\n\t}\n\tif exitErr, ok := err.(*exec.ExitError); ok {\n\t\tif status, ok := exitErr.Sys().(syscall.WaitStatus); ok {\n\t\t\treturn status.ExitStatus()\n\t\t}\n\t}\n\treturn -1\n\n}\n\nfunc checkCwd(cwd string) error {\n\tif cwd == \"\" {\n\t\treturn fmt.Errorf(\"cwd is empty\")\n\t}\n\tif _, err := os.Stat(cwd); err != nil {\n\t\treturn fmt.Errorf(\"error statting cwd %q: %w\", cwd, err)\n\t}\n\treturn nil\n}\n\ntype PipePty struct {\n\tremoteStdinWrite *os.File\n\tremoteStdoutRead *os.File\n}\n\nfunc (pp *PipePty) Fd() uintptr {\n\treturn pp.remoteStdinWrite.Fd()\n}\n\nfunc (pp *PipePty) Name() string {\n\treturn \"pipe-pty\"\n}\n\nfunc (pp *PipePty) Read(p []byte) (n int, err error) {","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/shellexec/shellexec.go#L97-L133","documentation":"checkCwd calls os.Stat(cwd) to confirm the working directory exists and is accessible. If Stat fails (missing directory, permission denied, or path pointing to a file), the error is wrapped as \"error statting cwd %q: %w\" including the offending path. This prevents the pty spawn from failing deep inside exec with a confusing error.","triggerScenarios":"StartLocalShellProc invoked with a cwd path that no longer exists (deleted directory), is a file instead of a directory, or is not readable due to permissions.","commonSituations":"User deleted or renamed the directory a block was running in; NFS/network mount offline; SSH remote whose directory vanished; cwd stored from a previous session on a different machine.","solutions":["os.Stat the cwd before starting the process and fall back to home directory if invalid","Restore/recreate the missing directory or fix permissions (chmod/chown)","Update the block's saved cwd to an existing path","If the path moved, migrate the stored cwd value"],"exampleFix":"// before\nproc, err := shellexec.StartLocalShellProc(ctx, termSize, cmdStr, cmdOpts, savedCwd)\n// after\nif _, err := os.Stat(savedCwd); err != nil {\n    savedCwd, _ = os.UserHomeDir()\n}\nproc, err := shellexec.StartLocalShellProc(ctx, termSize, cmdStr, cmdOpts, savedCwd)","handlingStrategy":"validation","validationCode":"info, err := os.Stat(cwd)\nif err != nil || !info.IsDir() {\n    cwd, _ = os.UserHomeDir() // fallback to a directory that exists\n}","typeGuard":null,"tryCatchPattern":"proc, err := shellexec.StartLocalShellProc(ctx, termSize, cmdStr, cmdOpts, cwd)\nif err != nil && strings.HasPrefix(err.Error(), \"error statting cwd\") {\n    cwd, _ = os.UserHomeDir()\n    proc, err = shellexec.StartLocalShellProc(ctx, termSize, cmdStr, cmdOpts, cwd)\n}","preventionTips":["Stat the cwd before spawn and fall back to home if invalid","Watch for directory deletion while a block is idle","Handle moved mounts/network paths by re-resolving cwd on reconnect"],"tags":["go","shell","cwd","filesystem"],"backgroundTag":"cwd-not-found","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}