coreybutler/nvm-windows · error
panic(ferr)
Error message
panic(ferr)
What it means
This panic fires when writeToErrorLog cannot append a message to error.log next to the executable. The function opens the log with os.ModePerm and, if the subsequent WriteString call fails, it panics instead of returning the error. Because this is the error-logging path itself, the panic masks the original error being logged and crashes the whole process.
Source
Thrown at src/nvm.go:85
node_mirror: "",
npm_mirror: "",
proxy: "none",
originalpath: "",
originalversion: "",
verifyssl: true,
}
func writeToErrorLog(i interface{}, abort ...bool) {
exe, _ := os.Executable()
file, err := os.OpenFile(filepath.Join(filepath.Dir(exe), "error.log"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, os.ModePerm)
if err != nil {
panic(err)
}
defer file.Close()
msg := fmt.Sprintf("%v\n", i)
if _, ferr := file.WriteString(msg); ferr != nil {
panic(ferr)
}
if len(abort) > 0 && abort[0] {
fmt.Println(msg)
os.Exit(1)
}
}
type Notification struct {
AppID string `json:"app_id"`
Title string `json:"title"`
Message string `json:"message"`
Icon string `json:"icon"`
Actions []Action `json:"actions"`
Duration string `json:"duration"`
Link string `json:"link"`
}
View on GitHub (pinned to 5b18223ca1)
Solutions
- Run the executable from a directory the process can write to (e.g. a user-owned install dir) so error.log is writable.
- Give the running user/group write permission on the executable's directory or pre-create error.log with appropriate ownership.
- Refactor writeToErrorLog to return an error (or log to stderr) instead of panicking, so a failed log write never crashes the app: fmt.Fprintln(os.Stderr, msg) as the fallback.
- Write the log to a writable location such as os.TempDir() or an env-configured path (e.g. NVM_HOME / XDG state dir) instead of filepath.Dir(exe).
- Free disk space / close other processes holding error.log if the failure is environmental.
Example fix
// before
if _, ferr := file.WriteString(msg); ferr != nil {
panic(ferr)
}
// after
if _, ferr := file.WriteString(msg); ferr != nil {
// never crash the process on the logging path itself
fmt.Fprintf(os.Stderr, "writeToErrorLog: failed to write error.log: %v (original message: %v)\n", ferr, i)
} Defensive patterns
Strategy: validation
Validate before calling
// Verify the error.log directory is writable before any logging can panic
func errorLogWritable() bool {
exe, err := os.Executable()
if err != nil {
return false
}
p := filepath.Join(filepath.Dir(exe), "error.log")
f, err := os.OpenFile(p, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
return false
}
return f.Close() == nil
} Prevention
- Run the binary from a user-writable directory so error.log can always be created/appended.
- Before calling APIs that log errors, check with a probe write that error.log is writable; fall back to stderr logging if not.
- Wrap the process entry point with a recover() that prints the panic and the original message to stderr instead of dying silently.
- Monitor free disk space on the executable's volume in long-running deployments.
When it happens
Trigger: Calling writeToErrorLog(msg) (or any wrapper such as a notification/log helper that routes through it) when: the directory containing the executable is read-only (e.g. /usr/bin, C:\Program Files); error.log is locked by another process on Windows; the disk is full; or the file is opened elsewhere with a conflicting lock. The open may succeed while WriteString fails on ENOSPC/EIO/permission races.
Common situations: Installing the Go binary into a protected system directory so the log file cannot be written; running as a service account without write permission to the exe folder; disk-full conditions on a long-running machine; antivirus/file-locking on Windows momentarily denying the write.
Related errors
- panic(err)
- Error rolling back node v%s installation: %v.
- Unable to move directory %s to node_modules: %v
- failed to set file permissions: %v
- failed to create destination directory %s: %v
AI-assisted analysis of coreybutler/nvm-windows@5b18223ca1 (2026-08-15).
Data as JSON: /api/errors/683c3118edcd503d.
Report an issue: GitHub.