JanDeDobbeleer/oh-my-posh · error

unable to write font file: %s

Error message

unable to write font file: %s

What it means

The Windows installer writes the font bytes to `fontsDir\font.FileName` with `os.WriteFile(..., 0644)` and wraps any write failure with this message. At this point the directory exists and any old file was removed, so failures are almost always permission, disk-space, or AV-interference issues.

Source

Thrown at src/cli/font/install_windows.go:53

		}
	}

	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)")

	k, _, err := registry.CreateKey(reg, `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts`, registry.WRITE)
	if err != nil {
		log.Error(err)
		// If this fails, remove the font file as well.
		if nexterr := os.Remove(fullPath); nexterr != nil {
			log.Error(nexterr)
			return errors.New("unable to delete font file after registry key open error")
		}

View on GitHub (pinned to 0976794618)

Solutions

  1. Run the terminal as Administrator for a machine-wide install, or use the default per-user install path (no elevation)
  2. Free disk space on the drive holding the fonts directory
  3. Temporarily exclude the fonts directory from real-time AV scanning and retry
  4. Retry — a transient file lock may have cleared
  5. Manually verify you can create a file in the fonts dir (`New-Item test.txt`) to confirm write access

Example fix

// before: non-elevated
PS> oh-my-posh font install FiraCode   # unable to write font file
// after
PS (admin)> oh-my-posh font install FiraCode
Defensive patterns

Strategy: validation

Validate before calling

# confirm write access and disk space first
$dir = "$env:LOCALAPPDATA\Microsoft\Windows\Fonts"
try { [IO.File]::WriteAllText("$dir\.wtest", "x"); Remove-Item "$dir\.wtest" }
catch { Write-Error "No write access to $dir"; exit 1 }
if ((Get-PSDrive ($dir[0]) ).Free -lt 50MB) { Write-Error 'Low disk space'; exit 1 }

Prevention

When it happens

Trigger: `os.WriteFile(fullPath, font.Data, 0644)` returns an error during `install` on Windows: access denied writing to C:\Windows\Fonts non-elevated, ERROR_DISK_FULL, or the just-removed file handle is still open by another process preventing recreation.

Common situations: Non-elevated shell attempting machine-wide install; full system drive; antivirus quarantine/race on newly created font files; another process re-created/locked the target path between Stat and WriteFile.

Understand the failure class

Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.

Related errors


AI-assisted analysis of JanDeDobbeleer/oh-my-posh@0976794618 (2026-08-31). Data as JSON: /api/errors/ea0f63f44b4c98b2. Report an issue: GitHub.