hashicorp/packer · error

failed to fetch

Error message

failed to fetch %s: %w

What it means

fetchStream performs the raw HTTP GET for remote registry streams (index.json, releases list, etc.). Any transport-level failure — DNS failure, connection refused, TLS error, timeout, context cancellation — is wrapped as "failed to fetch %s: %w" with the underlying cause preserved.

Solutions

  1. Check network connectivity and DNS resolution for the URL in the error message (curl it).
  2. Configure HTTPS_PROXY/HTTP_PROXY if egress requires a proxy.
  3. Retry if the failure was transient (timeouts, resets).
  4. Fix TLS trust (install the corporate CA) if the error is a certificate error.

Example fix

// before
export PACKER_PLUGIN_PATH=...  # behind proxy, fails
// after
export HTTPS_PROXY=http://proxy.corp:3128
packer plugins install ...
Defensive patterns

Strategy: retry

Validate before calling

u, err := url.Parse(registryURL)
if err != nil || u.Host == "" {
    return fmt.Errorf("invalid registry host")
}
if _, err := net.LookupHost(u.Hostname()); err != nil {
    return fmt.Errorf("cannot resolve %s; check network/DNS/proxy", u.Hostname())
}

Try / catch

var body io.ReadCloser
var err error
for i := 0; i < 3; i++ {
    body, err = g.Get("releases", opts)
    if err == nil || !isTransientNetErr(err) {
        break
    }
    time.Sleep(time.Duration(1<<i) * time.Second)
}

Prevention

When it happens

Trigger: g.HttpClient.Get(url) returns a non-nil error during Get/fetch — offline machine, unresolvable hostname, blocked egress, TLS interception, or a canceled context.

Common situations: No internet access or DNS failure when installing plugins; corporate firewall/proxy blocking releases.hashicorp.com or a custom registry host; expired/misconfigured TLS on a self-hosted registry; transient network flaps.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05). Data as JSON: /api/errors/00d480b7ff0cc0ec. Report an issue: GitHub.

Appendix: source

Thrown at packer/plugin-getter/remote/getter.go:126

		out = append(out, plugingetter.Release{Version: "v" + v})
	}
	buf := &bytes.Buffer{}
	if err := json.NewEncoder(buf).Encode(out); err != nil {
		return nil, err
	}
	return io.NopCloser(buf), nil
}

// fetchStream returns the response body of url for the caller to consume
// and close; fetch buffers it, for the small metadata files.
func (g *Getter) fetchStream(url string) (io.ReadCloser, error) {
	if g.HttpClient == nil {
		g.HttpClient = &http.Client{}
	}
	log.Printf("[DEBUG] remote-getter: getting %q", url)
	resp, err := g.HttpClient.Get(url)
	if err != nil {
		return nil, fmt.Errorf("failed to fetch %s: %w", url, err)
	}
	if resp.StatusCode >= 400 {
		_ = resp.Body.Close()
		return nil, fmt.Errorf("%s returned status %d", url, resp.StatusCode)
	}
	return resp.Body, nil
}

func (g *Getter) fetch(url string) ([]byte, error) {
	body, err := g.fetchStream(url)
	if err != nil {
		return nil, err
	}
	defer func() { _ = body.Close() }()
	return io.ReadAll(body)
}

// pluginPath returns the URL path of the plugin below the host, e.g.

View on GitHub (pinned to eb36e3c3e4)