coreybutler/nvm-windows · critical

panic(err)

Error message

panic(err)

What it means

writeToErrorLog() is nvm-windows' last-resort logger: it opens error.log next to the nvm executable. If os.OpenFile fails, it panics — crashing the whole command with a Go runtime panic instead of a clean error. It fires when the nvm installation directory is not writable: installed under Program Files without elevation, directory locked down by policy, or NVM_HOME on read-only media.

Source

Thrown at src/nvm.go:79

var env = &Environment{
	settings:        home,
	root:            "",
	symlink:         symlink,
	arch:            strings.ToLower(os.Getenv("PROCESSOR_ARCHITECTURE")),
	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"`

View on GitHub (pinned to 5b18223ca1)

Solutions

  1. Run the nvm command from an elevated (Administrator) prompt so error.log can be created.
  2. Install/relocate nvm to a user-writable directory (e.g. %APPDATA%\nvm or C:\nvm) and update NVM_HOME/NVM_SYMLINK and PATH.
  3. Verify the directory holding nvm.exe is writable: try creating a file there manually.
  4. As a code fix, replace panic with a graceful fallback (stderr + os.Exit(1)) so logging failure never crashes harder than the original error.

Example fix

// before
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)
}

// after: degrade gracefully — never crash the tool because logging failed
file, err := os.OpenFile(filepath.Join(filepath.Dir(exe), "error.log"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
    fmt.Fprintf(os.Stderr, "nvm: %v (additionally, could not write error.log: %v)\n", i, err)
    if len(abort) > 0 && abort[0] {
        os.Exit(1)
    }
    return
}
Defensive patterns

Strategy: fallback

Validate before calling

// Before running nvm, verify its directory is writable
exe, _ := os.Executable()
probe := filepath.Join(filepath.Dir(exe), ".write-probe")
if f, err := os.Create(probe); err != nil {
    return errors.New("nvm directory not writable — run elevated or relocate nvm")
} else { f.Close(); os.Remove(probe) }

Try / catch

// Wrap nvm invocations and treat a Go panic in writeToErrorLog as a permissions problem
out, err := cmd.CombinedOutput()
if err != nil && strings.Contains(string(out), "panic: ") && strings.Contains(string(out), "error.log") {
    return errors.New("nvm cannot write error.log — run from an elevated prompt")
}

Prevention

When it happens

Trigger: Any code path that logs via writeToErrorLog while the folder containing nvm.exe denies write access — most commonly running nvm non-elevated after installing to C:\Program Files\nodejs or similar protected locations.

Common situations: Corporate machines with locked-down Program Files; nvm.exe run from a read-only network share; NVM_HOME on a full or write-protected drive; antivirus blocking creation of error.log.

Related errors


AI-assisted analysis of coreybutler/nvm-windows@5b18223ca1 (2026-08-15). Data as JSON: /api/errors/52d1d5720f1ac52e. Report an issue: GitHub.