wavetermdev/waveterm · error

error writing bash-integration bash_preexec.sh: %v

Error message

error writing bash-integration bash_preexec.sh: %v

What it means

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.

Source

Thrown at pkg/util/shellutil/shellutil.go:415

	err = utilfn.WriteTemplateToFile(filepath.Join(zshDir, ".zshrc"), ZshStartup_Zshrc, params)
	if err != nil {
		return fmt.Errorf("error writing zsh-integration .zshrc: %v", err)
	}
	err = utilfn.WriteTemplateToFile(filepath.Join(zshDir, ".zlogin"), ZshStartup_Zlogin, params)
	if err != nil {
		return fmt.Errorf("error writing zsh-integration .zlogin: %v", err)
	}
	err = utilfn.WriteTemplateToFile(filepath.Join(zshDir, ".zshenv"), ZshStartup_Zshenv, params)
	if err != nil {
		return fmt.Errorf("error writing zsh-integration .zshenv: %v", err)
	}
	err = utilfn.WriteTemplateToFile(filepath.Join(bashDir, ".bashrc"), BashStartup_Bashrc, params)
	if err != nil {
		return fmt.Errorf("error writing bash-integration .bashrc: %v", err)
	}
	err = os.WriteFile(filepath.Join(bashDir, "bash_preexec.sh"), []byte(BashStartup_Preexec), 0644)
	if err != nil {
		return fmt.Errorf("error writing bash-integration bash_preexec.sh: %v", err)
	}
	err = utilfn.WriteTemplateToFile(filepath.Join(fishDir, "wave.fish"), FishStartup_Wavefish, params)
	if err != nil {
		return fmt.Errorf("error writing fish-integration wave.fish: %v", err)
	}
	err = utilfn.WriteTemplateToFile(filepath.Join(pwshDir, "wavepwsh.ps1"), PwshStartup_wavepwsh, params)
	if err != nil {
		return fmt.Errorf("error writing pwsh-integration wavepwsh.ps1: %v", err)
	}

	return nil
}

func initCustomShellStartupFilesInternal() error {
	log.Printf("initializing wsh and shell startup files\n")
	waveDataHome := wavebase.GetWaveDataDir()
	binDir := filepath.Join(waveDataHome, WaveHomeBinDir)
	err := InitRcFiles(waveDataHome, binDir)

View on GitHub (pinned to a4447c1563)

Solutions

  1. Check and fix permissions/ownership on the bash-integrations directory and bash_preexec.sh.
  2. Remove immutable/lock attributes (chattr -i on Linux; exclude wave dirs from AV on Windows).
  3. Delete bash_preexec.sh and let Wave rewrite it on next init.
  4. Confirm the parent dir exists (CacheEnsureDir succeeded) and the disk is not full.

Example fix

// before
$ lsattr ~/.waveterm/bash-integrations/bash_preexec.sh  # ----i--------
// after
$ chattr -i ~/.waveterm/bash-integrations/bash_preexec.sh && wave
Defensive patterns

Strategy: validation

Validate before calling

// check existing bash_preexec.sh is replaceable
preexec := filepath.Join(bashDir, "bash_preexec.sh")
if fi, err := os.Stat(preexec); err == nil {
	if fi.Mode().Perm()&0200 == 0 { os.Chmod(preexec, 0644) }
}
if err := unix.Access(bashDir, unix.W_OK); err != nil { return err }

Try / catch

if err := shellutil.InitRcFiles(home, binDir); err != nil {
	if strings.Contains(err.Error(), "bash_preexec.sh") {
		os.Remove(filepath.Join(bashDir, "bash_preexec.sh"))
		return shellutil.InitRcFiles(home, binDir) // one retry after removing blocker
	}
	return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/847dae38352c2de9. Report an issue: GitHub.