JanDeDobbeleer/oh-my-posh · error
unable to remove existing font file: %s
Error message
unable to remove existing font file: %s
What it means
Before writing the new font file, the Windows `install` routine removes a previously installed font with the same filename. This error wraps `os.Remove(fullPath)` failing on that existing file — typically because the font is locked by a running application or the process lacks delete permission.
Source
Thrown at src/cli/font/install_windows.go:45
fontsDir := filepath.Join(os.Getenv("USERPROFILE"), "AppData", "Local", "Microsoft", "Windows", "Fonts")
log.Debugf("installing font %s to %s", font.FileName, fontsDir)
// check if the Fonts folder exists, if not, create it
if _, err := os.Stat(fontsDir); os.IsNotExist(err) {
if err = os.MkdirAll(fontsDir, 0755); err != nil {
return fmt.Errorf("unable to create fonts directory: %s", err.Error())
}
}
log.Debug("fonts directory exists, proceeding with installation")
fullPath := filepath.Join(fontsDir, font.FileName)
// validate if the font is already installed, remove it in case it is
if _, err := os.Stat(fullPath); err == nil {
log.Debugf("font %s already exists, removing it", fullPath)
if err = os.Remove(fullPath); err != nil {
return fmt.Errorf("unable to remove existing font file: %s", err.Error())
}
}
log.Debugf("writing font file to %s", fullPath)
err := os.WriteFile(fullPath, font.Data, 0644)
if err != nil {
return fmt.Errorf("unable to write font file: %s", err.Error())
}
log.Debug("font file written successfully, proceeding with registry entry")
// Add registry entry
reg := registry.CURRENT_USER
regValue := fullPath
log.Debug("opening HKEY_CURRENT_USER for writing (SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts)")
View on GitHub (pinned to 0976794618)
Solutions
- Close applications using the font (browsers, editors, the terminal itself) and retry
- Run elevated if the existing file is in C:\Windows\Fonts
- Clear the read-only attribute: `attrib -r "<fullPath>"` then retry
- Reboot (or restart explorer.exe) to release GDI font handles, then reinstall
- Manually delete the old font via Settings > Fonts, then run the installer again
Example fix
// before PS> oh-my-posh font install FiraCode # file locked by running app // after: close apps / release handle, or PS> attrib -r "$env:LOCALAPPDATA\Microsoft\Windows\Fonts\FiraCode-Regular.ttf" PS> oh-my-posh font install FiraCode
Defensive patterns
Strategy: validation
Validate before calling
# pre-check that the existing font file is deletable
$path = "$env:LOCALAPPDATA\Microsoft\Windows\Fonts\FiraCode-Regular.ttf"
if (Test-Path $path) {
try { $fs=[IO.File]::Open($path,'Open','ReadWrite','None'); $fs.Close() }
catch { Write-Error "Font file is locked: $path"; exit 1 }
} Prevention
- Close apps that load fonts (browsers, editors, terminal) before reinstalling
- Clear read-only attributes on font files before automated reinstalls
- Run elevated when replacing fonts in C:\Windows\Fonts
When it happens
Trigger: `os.Stat(fullPath)` succeeds (font already installed), then `os.Remove(fullPath)` returns an error: file in use (loaded by GDI/DirectWrite in a running app), read-only attribute, or ACL denies delete (machine fonts dir without elevation).
Common situations: Reinstalling/upgrading a font that Word/Photoshop/your terminal currently has loaded; SYSTEM-owned file in C:\Windows\Fonts installed by another admin; read-only attribute set on the old file.
Related errors
- unable to delete font file after registry key open error
- unable to delete font file after registry key set error
- failed to convert file path to UTF16: %v
- unable to create fonts directory: %s
- unable to write font file: %s
AI-assisted analysis of JanDeDobbeleer/oh-my-posh@0976794618 (2026-08-31).
Data as JSON: /api/errors/9d97b9dae2682419.
Report an issue: GitHub.