{"record":{"id":"efde1167c8298819","repo":"wavetermdev/waveterm","slug":"error-copying-wsh-binary-to-bin-v","errorCode":null,"errorMessage":"error copying wsh binary to bin: %v","messagePattern":"error copying wsh binary to bin: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/util/shellutil/shellutil.go","lineNumber":458,"sourceCode":"\t\treturn err\n\t}\n\n\t// copy the correct binary to bin\n\twshFullPath, err := GetLocalWshBinaryPath(wavebase.WaveVersion, runtime.GOOS, runtime.GOARCH)\n\tif err != nil {\n\t\tlog.Printf(\"error (non-fatal), could not resolve wsh binary path: %v\\n\", err)\n\t}\n\tif _, err := os.Stat(wshFullPath); err != nil {\n\t\tlog.Printf(\"error (non-fatal), could not resolve wsh binary %q: %v\\n\", wshFullPath, err)\n\t\treturn nil\n\t}\n\twshDstPath := filepath.Join(binDir, \"wsh\")\n\tif runtime.GOOS == \"windows\" {\n\t\twshDstPath = wshDstPath + \".exe\"\n\t}\n\terr = utilfn.AtomicRenameCopy(wshDstPath, wshFullPath, 0755)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error copying wsh binary to bin: %v\", err)\n\t}\n\twshBaseName := filepath.Base(wshFullPath)\n\tlog.Printf(\"wsh binary successfully copied from %q to %q\\n\", wshBaseName, wshDstPath)\n\treturn nil\n}\n\nfunc GetShellTypeFromShellPath(shellPath string) string {\n\tshellBase := filepath.Base(shellPath)\n\tif strings.Contains(shellBase, \"bash\") {\n\t\treturn ShellType_bash\n\t}\n\tif strings.Contains(shellBase, \"zsh\") {\n\t\treturn ShellType_zsh\n\t}\n\tif strings.Contains(shellBase, \"fish\") {\n\t\treturn ShellType_fish\n\t}\n\tif strings.Contains(shellBase, \"pwsh\") || strings.Contains(shellBase, \"powershell\") {","sourceCodeStart":440,"sourceCodeEnd":476,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/util/shellutil/shellutil.go#L440-L476","documentation":"initCustomShellStartupFilesInternal copies the platform-appropriate wsh binary into <waveDataHome>/bin via utilfn.AtomicRenameCopy (write temp + rename). This error wraps any failure in that copy: source missing/unreadable, destination not writable, cross-device rename issues, or target binary in use (ETXTBSY/Windows lock).","triggerScenarios":"Calling initCustomShellStartupFilesInternal (wsh init path) when AtomicRenameCopy(wshDstPath, wshFullPath, 0755) fails: wshFullPath missing despite passing os.Stat, bin dir unwritable, or rename across filesystems.","commonSituations":"Upgraded Wave package where the bundled wsh path changed; running Wave from a read-only install while the data dir is elsewhere; two Wave instances racing to replace wsh simultaneously; EPERM when overwriting a running executable on Windows.","solutions":["Verify the source binary exists via GetLocalWshBinaryPath(wavebase.WaveVersion, GOOS, GOARCH) and reinstall/repair Wave if missing.","Check write permission and free space on the wave bin dir (<data>/bin); fix ownership.","Stop other running Wave instances/wsh processes that may hold the destination binary open, then retry.","If the source-stat guard silently skipped (non-fatal log path), rerun after the wsh binary is properly installed."],"exampleFix":"// before: stale running wsh holds the destination lock\n$ pkill wsh && wave  # then init succeeds\n// after\nwsh binary successfully copied from \"wsh\" to \".../bin/wsh\"","handlingStrategy":"retry","validationCode":"// pre-check source and destination before the copy\nsrc, _ := shellutil.GetLocalWshBinaryPath(version, runtime.GOOS, runtime.GOARCH)\nif _, err := os.Stat(src); err != nil { return fmt.Errorf(\"wsh source missing: %w\", err) }\nif err := os.MkdirAll(binDir, 0755); err != nil { return err }","typeGuard":null,"tryCatchPattern":"err := shellutil.InitCustomShellStartupFiles() // or the internal init\nif err != nil && strings.Contains(err.Error(), \"error copying wsh binary\") {\n\ttime.Sleep(500 * time.Millisecond) // let AV/running-process lock release\n\tif retryErr := shellutil.InitCustomShellStartupFiles(); retryErr != nil {\n\t\treturn retryErr\n\t}\n}","preventionTips":["Ensure only one Wave instance performs wsh initialization at a time (single-instance lock).","Reinstall/repair Wave if the bundled wsh binary path is missing for the current version/arch.","On Windows, exit running wsh processes before upgrading so the destination isn't locked.","Keep the wave data dir and the install on the same filesystem to avoid rename edge cases."],"tags":["filesystem","wsh","binary-copy","atomic-rename"],"backgroundTag":"binary-copy-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}