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://{hostname}/api/v4/projects/{url.QueryEscape(owner + "/" + repo)} — for gitlab.com that is the public projects endpoint. As with any net/http transport error, it means DNS, connection, TLS, or proxy failure; no HTTP response was obtained, so no status code exists yet.

Source

Thrown at gitlab.go:32

func findGitLabREADME(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())
	}

	projectPath := url.QueryEscape(owner + "/" + repo)

	type readme struct {
		ReadmeURL string `json:"readme_url"`
	}

	apiURL := fmt.Sprintf("https://%s/api/v4/projects/%s", u.Hostname(), projectPath)

	//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)
	}

	readmeRawURL := strings.ReplaceAll(result.ReadmeURL, "blob", "raw")

	if res.StatusCode == http.StatusOK {
		//nolint:bodyclose
		// it is closed on the caller
		resp, err := http.Get(readmeRawURL) //nolint: gosec,noctx

View on GitHub (pinned to e3970c813d)

Solutions

  1. Test reachability: curl -v "https://gitlab.com/api/v4/projects/owner%2Frepo"
  2. Fix or unset HTTPS_PROXY/HTTP_PROXY if the proxy is the failure point
  3. Install the proxy's CA into the system trust store (update-ca-certificates / update-ca-trust)
  4. For self-hosted GitLab, confirm the hostname resolves from this machine and is not VPN-only; otherwise run glow on local files

Example fix

# before
glow https://gitlab.com/owner/repo
# Error: unable to get url: Get "https://gitlab.com/api/v4/...": dial tcp: lookup gitlab.com: no such host

# after
$ resolvectl flush-caches && curl -sI https://gitlab.com >/dev/null && glow https://gitlab.com/owner/repo
Defensive patterns

Strategy: retry

Validate before calling

// confirm the projects endpoint answers before invoking glow
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
probe := fmt.Sprintf("https://%s/api/v4/projects", u.Hostname())
req, _ := http.NewRequestWithContext(ctx, http.MethodHead, probe, nil)
if _, err := http.DefaultClient.Do(req); err != nil {
	return fmt.Errorf("%s unreachable (DNS/proxy/firewall?): %w", probe, err)
}

Try / catch

err := retry(3, 400*time.Millisecond, func() error {
	var err error
	src, err = findGitLabREADME(u)
	if err != nil && strings.Contains(err.Error(), "unable to get url") {
		var ue *url.Error
		if errors.As(err, &ue) && (ue.Timeout() || errors.Is(ue, syscall.ECONNREFUSED) || errors.Is(ue, syscall.EAI_AGAIN)) {
			return err // transport-level: retry with backoff
		}
	}
	return err
})
if err != nil {
	return nil, fmt.Errorf("gitlab api unreachable after retries: %w", err)
}

Prevention

When it happens

Trigger: DNS failure resolving gitlab.com; blocked or timed-out connection to port 443; HTTPS_PROXY pointing at an unreachable proxy; TLS interception with an untrusted CA breaking the handshake; self-hosted GitLab hostnames that do not resolve or are internal-only.

Common situations: Firewalled/air-gapped environments without GitLab egress; corporate proxies requiring custom CAs not in the system trust store; VPN split-tunnel dropping the GitLab route; containers missing CA certificates.

Related errors


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