pocketbase/pocketbase · error

failed to rename the current executable: %w

Error message

failed to rename the current executable: %w

What it means

ghupdate: the first step of replacing the running executable — os.Rename(oldExec, oldExec+".old") — failed. On this failure nothing has been changed yet (the defer removes the .old name if it exists). Wrapped with %w so the OS-level rename error (permissions, cross-device, text-file-busy equivalents) is preserved.

Source

Thrown at plugins/ghupdate/ghupdate.go:222

	oldExec, err := os.Executable()
	if err != nil {
		return err
	}
	renamedOldExec := oldExec + ".old"
	defer os.Remove(renamedOldExec)

	newExec := filepath.Join(extractDir, p.config.ArchiveExecutable)
	if _, err := os.Stat(newExec); err != nil {
		// try again with an .exe extension
		newExec = newExec + ".exe"
		if _, fallbackErr := os.Stat(newExec); fallbackErr != nil {
			return fmt.Errorf("the executable in the extracted path is missing or it is inaccessible: %v, %v", err, fallbackErr)
		}
	}

	// rename the current executable
	if err := os.Rename(oldExec, renamedOldExec); err != nil {
		return fmt.Errorf("failed to rename the current executable: %w", err)
	}

	tryToRevertExecChanges := func() {
		if revertErr := os.Rename(renamedOldExec, oldExec); revertErr != nil {
			p.app.Logger().Debug(
				"Failed to revert executable",
				slog.String("old", renamedOldExec),
				slog.String("new", oldExec),
				slog.String("error", revertErr.Error()),
			)
		}
	}

	// replace with the extracted binary
	if err := os.Rename(newExec, oldExec); err != nil {
		tryToRevertExecChanges()
		return fmt.Errorf("failed replacing the executable: %w", err)
	}

View on GitHub (pinned to 5d217ddb50)

Solutions

  1. Check the wrapped error for EACCES/EROFS and grant write permission on the binary's directory to the app user
  2. Move the executable to a writable location (e.g. a data volume) before using the updater
  3. On locked/managed hosts, disable ghupdate and update via your package/deploy pipeline

Example fix

# before
sudo mv pocketbase /usr/local/bin/ && /usr/local/bin/pocketbase update  # EACCES
# after
sudo chown $(whoami) /usr/local/bin/pocketbase  # or place it in a user-writable dir
./pocketbase update
Defensive patterns

Strategy: validation

Validate before calling

// ensure the binary's directory is writable before enabling self-update
execPath, _ := os.Executable()
if err := unix.Access(filepath.Dir(execPath), unix.W_OK); err != nil {
    log.Println("self-update disabled: install dir not writable")
}

Try / catch

if err := updater.Update(ctx, false); err != nil {
    if strings.Contains(err.Error(), "failed to rename the current executable") {
        // EACCES/EROFS: fix dir permissions or relocate binary; nothing was changed yet
    }
}

Prevention

When it happens

Trigger: The running binary's file or its directory is not writable by the process; on Windows the executable may be locked; on Linux a read-only mount or no write permission on the install dir. Note rename stays on one filesystem, so EXDEV is unlikely unless the .old path is redirected.

Common situations: Binary installed in /usr/local/bin or /opt owned by root while the app runs unprivileged; container images with the binary on a read-only layer; SELinux denying rename on the exec type.

Related errors


AI-assisted analysis of pocketbase/pocketbase@5d217ddb50 (2026-08-15). Data as JSON: /api/errors/fbfecaa6abe10051. Report an issue: GitHub.