gohugoio/hugo · error
failed to fetch remote resource from '%s': %s
Error message
failed to fetch remote resource from '%s': %s
What it means
The remote fetch completed but the server answered with a non-2xx status (other than 404, which Hugo maps to a nil resource to mirror missing local resources). Hugo wraps the status text into an HTTP error carrying the response so templates can inspect it via `.Err`. This is a server-side/authorization problem, not a Hugo bug.
Source
Thrown at resources/resource_factories/create/remote.go:286
if cancel != nil {
defer cancel()
}
if err != nil {
return nil, err
}
defer res.Body.Close()
c.configurePollingIfEnabled(uri, optionsKey, getRes)
if res.StatusCode == http.StatusNotFound {
// Not found. This matches how lookups for local resources work.
// To cache this, we need to make sure the body is read.
io.Copy(io.Discard, res.Body)
return nil, nil
}
if res.StatusCode < 200 || res.StatusCode > 299 {
return nil, toHTTPError(fmt.Errorf("failed to fetch remote resource from '%s': %s", uri, http.StatusText(res.StatusCode)), res, !isHeadMethod, options.ResponseHeaders)
}
var (
body []byte
mediaType media.Type
)
// A response to a HEAD method should not have a body. If it has one anyway, that body must be ignored.
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD
if !isHeadMethod && res.Body != nil {
body, err = io.ReadAll(res.Body)
if err != nil {
return nil, fmt.Errorf("failed to read remote resource %q: %w", uri, err)
}
}
filename := path.Base(rURL.Path)
if _, params, _ := mime.ParseMediaType(res.Header.Get("Content-Disposition")); params != nil {
if _, ok := params["filename"]; ok {View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Handle it gracefully in the template: check `.Err` on the returned resource (`{{ with try (resources.GetRemote $u) }}...`) and log via `errorf`/`warnf` instead of crashing the build.
- Add required auth/User-Agent headers via the options dict and ensure CI secrets are actually set.
- For 429s, authenticate to raise rate limits or cache the response (use a stable `key` option) so rebuilds don't refetch.
- Verify the URL responds correctly with `curl -i` from the same environment as the build.
Example fix
{{/* before */}}
{{ $data := resources.GetRemote $u | transform.Unmarshal }}
{{/* after */}}
{{ with resources.GetRemote $u (dict "headers" (dict "Authorization" (printf "Bearer %s" (getenv "API_TOKEN")))) }}
{{ with .Err }}{{ errorf "remote fetch failed: %s" . }}{{ else }}{{ $data := . | transform.Unmarshal }}{{ end }}
{{ end }} Defensive patterns
Strategy: fallback
Try / catch
{{/* GetRemote does not fail the build by default — check .Err yourself */}}
{{ $r := resources.GetRemote $url }}
{{ with $r }}
{{ with .Err }}
{{ warnf "remote fetch failed: %s — using local fallback" . }}
{{ $r = resources.Get "fallback/placeholder.svg" }}
{{ end }}
{{ end }} Prevention
- Always check .Err on the result of resources.GetRemote; a non-2xx status surfaces there
- Decide explicitly per call: errorf (fail build) for critical assets, warnf + committed local fallback for optional ones — Hugo builds are offline-hostile in CI
- Cache remote resources (resources/_gen committed or CI cache) so transient upstream outages don't break builds
- Send required auth headers; 401/403 responses appear as this fetch error
When it happens
Trigger: `resources.GetRemote` receiving 401/403 (missing or invalid auth headers), 429 (rate limiting, common with GitHub/API endpoints during CI builds), 5xx from the origin, or 3xx loops the client won't follow — anything outside 200–299 except 404.
Common situations: Expired or unset API tokens in CI environment variables, GitHub API rate limits on unauthenticated builds, hotlink protection or bot blocking (Cloudflare 403) against Hugo's requests, endpoints requiring a User-Agent header, or transient upstream outages during site builds.
Related errors
- failed to read remote resource %q: %w
- failed to download modules: %w
- failed to get remote ref %q: %w
- must provide an URL and optionally an options map
- stopped after 10 redirects
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/73edc44a7de603b1.json.
Report an issue: GitHub ↗.