JanDeDobbeleer/oh-my-posh · error

is not a valid zip file

Error message

%s is not a valid zip file

What it means

oh-my-posh's font downloader (`oh-my-posh font download <name>`) fetches a font archive from a remote URL and validates it is a ZIP before extracting. This error means the bytes downloaded from `fontURL` failed the ZIP magic-number check (`isZipFile`), so the installer refuses to process the payload. It guards against HTML error pages, redirects to login pages, or corrupted transfers being treated as font archives.

Solutions

  1. Verify the URL returns a real .zip: `curl -sIL <url>` and check Content-Type (application/zip) and size
  2. Re-run the command — a transient proxy/cache issue may have served a bad body
  3. Use an official release asset URL (e.g. a Nerd Fonts release zip) rather than a repo page URL
  4. Check for corporate proxy interference (set HTTP(S)_PROXY correctly or bypass it)
  5. If persistent, report the URL at github.com/JanDeDobbeleer/oh-my-posh/issues

Example fix

// before: URL to an HTML release page
oh-my-posh font download "https://github.com/ryanoasis/nerd-fonts/releases"
// after: URL to the actual zip asset
oh-my-posh font download "https://github.com/ryanoasis/nerd-fonts/releases/download/v3.2.1/FiraCode.zip"
Defensive patterns

Strategy: validation

Validate before calling

func isZip(path string) error {
	f, err := os.Open(path)
	if err != nil {
		return err
	}
	defer f.Close()
	magic := make([]byte, 2)
	if _, err := io.ReadFull(f, magic); err != nil {
		return err
	}
	if magic[0] != 'P' || magic[1] != 'K' {
		return fmt.Errorf("%s is not a zip file", path)
	}
	return nil
}
// run isZip() on the URL's payload (or curl -sI and check Content-Type: application/zip) before installing

Try / catch

if err := fontDownload(url); err != nil {
	if strings.Contains(err.Error(), "is not a valid zip file") {
		// inspect URL / retry with the canonical release asset URL
	}
}

Prevention

When it happens

Trigger: `download(fontURL, report)` calls `getRemoteFile` successfully (HTTP 200) but the response body does not start with the ZIP signature (PK). Typical when the URL points to an HTML page instead of the archive, a CDN/proxy returns an error or captcha page with status 200, or the file is a .tar.gz instead of a .zip.

Common situations: GitHub codeload URL changed or redirected to an HTML page; corporate proxy/SSL-inspection appliance substituting a block page; manually specified URL for a release asset that is actually a tarball; truncated download served with 200 OK.

Related errors


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

Appendix: source

Thrown at src/cli/font/download.go:40

	if zipPath, OK := cache.Device.Get[string](fontURL); OK {
		if b, err := os.ReadFile(zipPath); err == nil {
			return b, nil
		}
	}

	// validate if we have a local file
	u, err := url.Parse(fontURL)
	if err != nil || u.Scheme != "https" {
		return nil, errors.New("font path must be a valid URL")
	}

	var b []byte
	if b, err = getRemoteFile(fontURL, report); err != nil {
		return nil, err
	}

	if !isZipFile(b) {
		return nil, fmt.Errorf("%s is not a valid zip file", fontURL)
	}

	fileName := path.Base(fontURL)

	zipPath := filepath.Join(os.TempDir(), fileName)
	tempFile, err := os.Create(zipPath)
	defer func() {
		_ = tempFile.Close()
	}()

	if err != nil {
		return b, nil
	}

	_, err = tempFile.Write(b)
	if err != nil {
		return b, nil
	}

View on GitHub (pinned to 0976794618)