charmbracelet/glow · error

unable to get url: %w

Error message

unable to get url: %w

What it means

This wraps the failure of http.Get(apiURL) where apiURL is https://api.{hostname}/repos/{owner}/{repo}/readme. The error is a *url.Error from net/http: DNS resolution failure, connection refused/timeout, TLS handshake error, or proxy failure. Nothing was received from the API, so no status code exists yet.

Source

Thrown at github.go:30

// findGitHubREADME tries to find the correct README filename in a repository using GitHub API.
func findGitHubREADME(u *url.URL) (*source, error) {
	owner, repo, ok := strings.Cut(strings.TrimPrefix(u.Path, "/"), "/")
	if !ok {
		return nil, fmt.Errorf("invalid url: %s", u.String())
	}

	type readme struct {
		DownloadURL string `json:"download_url"`
	}

	apiURL := fmt.Sprintf("https://api.%s/repos/%s/%s/readme", u.Hostname(), owner, repo)

	//nolint:bodyclose
	// it is closed on the caller
	res, err := http.Get(apiURL) //nolint: gosec,noctx
	if err != nil {
		return nil, fmt.Errorf("unable to get url: %w", err)
	}

	body, err := io.ReadAll(res.Body)
	if err != nil {
		return nil, fmt.Errorf("unable to read http response body: %w", err)
	}

	var result readme
	if err := json.Unmarshal(body, &result); err != nil {
		return nil, fmt.Errorf("unable to parse json: %w", err)
	}

	if res.StatusCode == http.StatusOK {
		//nolint:bodyclose
		// it is closed on the caller
		resp, err := http.Get(result.DownloadURL) //nolint: noctx
		if err != nil {
			return nil, fmt.Errorf("unable to get url: %w", err)

View on GitHub (pinned to e3970c813d)

Solutions

  1. Test reachability: curl -v https://api.github.com/repos/OWNER/REPO/readme
  2. Check proxy env: env | grep -i proxy and fix or unset HTTPS_PROXY
  3. Install/refresh the system CA bundle if TLS verification fails
  4. Allow egress to api.github.com:443 in firewall/sandbox rules, or run glow offline on local files

Example fix

# before
glow https://github.com/owner/repo
# Error: unable to get url: Get "https://api.github.com/...": proxyconnect tcp: connection refused

# after
$ unset HTTPS_PROXY http_proxy && glow https://github.com/owner/repo
Defensive patterns

Strategy: retry

Validate before calling

// cheap liveness probe before handing the URL to glow
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, http.MethodHead, "https://api.github.com", nil)
if _, err := http.DefaultClient.Do(req); err != nil {
	return fmt.Errorf("api.github.com unreachable (check network/proxy): %w", err)
}

Try / catch

var src *source
err := retry(3, 500*time.Millisecond, func() error {
	var err error
	src, err = findGitHubREADME(u)
	if err != nil && strings.Contains(err.Error(), "unable to get url") {
		var ue *url.Error
		if errors.As(err, &ue) && (errors.Is(ue, context.DeadlineExceeded) || ue.Timeout() || errors.Is(ue, syscall.ECONNREFUSED)) {
			return err // transient transport failure: retry
		}
	}
	return err // anything else: stop
})

func retry(n int, d time.Duration, fn func() error) error {
	var err error
	for i := 0; i < n; i++ {
		if err = fn(); err == nil {
			return nil
		}
		time.Sleep(d << i)
	}
	return err
}

Prevention

When it happens

Trigger: No network or DNS failure resolving api.github.com; HTTPS_PROXY/HTTP_PROXY pointing at a dead proxy; TLS interception with an untrusted CA (corporate MITM) failing verification; firewall dropping outbound 443; IPv6-only misconfiguration causing dial timeouts.

Common situations: Airports/captive portals; corporate proxies with expired certs; containers without CA certificates (update-ca-certificates); sandboxes that block egress (must allow api.github.com:443).

Related errors


AI-assisted analysis of charmbracelet/glow@e3970c813d (2026-08-15). Data as JSON: /api/errors/e9c6d08c5b0a68c1. Report an issue: GitHub.