{"record":{"id":"847dae38352c2de9","repo":"wavetermdev/waveterm","slug":"error-writing-bash-integration-bash-preexec-sh-v","errorCode":null,"errorMessage":"error writing bash-integration bash_preexec.sh: %v","messagePattern":"error writing bash-integration bash_preexec\\.sh: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/util/shellutil/shellutil.go","lineNumber":415,"sourceCode":"\terr = utilfn.WriteTemplateToFile(filepath.Join(zshDir, \".zshrc\"), ZshStartup_Zshrc, params)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error writing zsh-integration .zshrc: %v\", err)\n\t}\n\terr = utilfn.WriteTemplateToFile(filepath.Join(zshDir, \".zlogin\"), ZshStartup_Zlogin, params)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error writing zsh-integration .zlogin: %v\", err)\n\t}\n\terr = utilfn.WriteTemplateToFile(filepath.Join(zshDir, \".zshenv\"), ZshStartup_Zshenv, params)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error writing zsh-integration .zshenv: %v\", err)\n\t}\n\terr = utilfn.WriteTemplateToFile(filepath.Join(bashDir, \".bashrc\"), BashStartup_Bashrc, params)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error writing bash-integration .bashrc: %v\", err)\n\t}\n\terr = os.WriteFile(filepath.Join(bashDir, \"bash_preexec.sh\"), []byte(BashStartup_Preexec), 0644)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error writing bash-integration bash_preexec.sh: %v\", err)\n\t}\n\terr = utilfn.WriteTemplateToFile(filepath.Join(fishDir, \"wave.fish\"), FishStartup_Wavefish, params)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error writing fish-integration wave.fish: %v\", err)\n\t}\n\terr = utilfn.WriteTemplateToFile(filepath.Join(pwshDir, \"wavepwsh.ps1\"), PwshStartup_wavepwsh, params)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error writing pwsh-integration wavepwsh.ps1: %v\", err)\n\t}\n\n\treturn nil\n}\n\nfunc initCustomShellStartupFilesInternal() error {\n\tlog.Printf(\"initializing wsh and shell startup files\\n\")\n\twaveDataHome := wavebase.GetWaveDataDir()\n\tbinDir := filepath.Join(waveDataHome, WaveHomeBinDir)\n\terr := InitRcFiles(waveDataHome, binDir)","sourceCodeStart":397,"sourceCodeEnd":433,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/util/shellutil/shellutil.go#L397-L433","documentation":"InitRcFiles fails while writing bash_preexec.sh via a plain os.WriteFile (0644), not the templating helper. This is the raw OS write error wrapped with context; it indicates the bash-integrations directory is not writable or the file cannot be created/replaced.","triggerScenarios":"InitRcFiles or InstallRcFiles hitting the os.WriteFile(bash_preexec.sh) call with a non-writable bashDir, an existing bash_preexec.sh that cannot be truncated, or a missing parent directory.","commonSituations":"bash_preexec.sh made immutable (chattr +i) by hardening tools; dir ownership mismatch after running Wave as different users; Windows file-lock by AV while Wave rewrites the file.","solutions":["Check and fix permissions/ownership on the bash-integrations directory and bash_preexec.sh.","Remove immutable/lock attributes (chattr -i on Linux; exclude wave dirs from AV on Windows).","Delete bash_preexec.sh and let Wave rewrite it on next init.","Confirm the parent dir exists (CacheEnsureDir succeeded) and the disk is not full."],"exampleFix":"// before\n$ lsattr ~/.waveterm/bash-integrations/bash_preexec.sh  # ----i--------\n// after\n$ chattr -i ~/.waveterm/bash-integrations/bash_preexec.sh && wave","handlingStrategy":"validation","validationCode":"// check existing bash_preexec.sh is replaceable\npreexec := filepath.Join(bashDir, \"bash_preexec.sh\")\nif fi, err := os.Stat(preexec); err == nil {\n\tif fi.Mode().Perm()&0200 == 0 { os.Chmod(preexec, 0644) }\n}\nif err := unix.Access(bashDir, unix.W_OK); err != nil { return err }","typeGuard":null,"tryCatchPattern":"if err := shellutil.InitRcFiles(home, binDir); err != nil {\n\tif strings.Contains(err.Error(), \"bash_preexec.sh\") {\n\t\tos.Remove(filepath.Join(bashDir, \"bash_preexec.sh\"))\n\t\treturn shellutil.InitRcFiles(home, binDir) // one retry after removing blocker\n\t}\n\treturn err\n}","preventionTips":["Look for immutable flags (lsattr) on integration files after hardening audits.","Close processes that may hold bash_preexec.sh open (editors, long-lived shells sourcing it).","Ensure CacheEnsureDir ran successfully before file writes.","Keep bash-integrations out of backup tools that set read-only attributes."],"tags":["filesystem","shell-integration","bash","file-write"],"backgroundTag":"file-write-permission-denied","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}