hashicorp/packer · error
failed to fetch %s: %w
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.
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)
Solutions
- Check network connectivity and DNS resolution for the URL in the error message (curl it).
- Configure HTTPS_PROXY/HTTP_PROXY if egress requires a proxy.
- Retry if the failure was transient (timeouts, resets).
- 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
- Verify HTTPS_PROXY/NO_PROXY are set in restricted networks.
- Precheck DNS/connectivity to the registry host before installs.
- Install corporate CA certs when behind TLS inspection.
- Retry transient failures with exponential backoff.
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
- %q not implemented
- could not parse release: %w
- could not find a local nor a remote checksum for plugin %q %
- transformReleasesVersionStream got nil body
- %q not implemented
AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05).
Data as JSON: /api/errors/00d480b7ff0cc0ec.
Report an issue: GitHub.