gohugoio/hugo · error

failed to read remote resource %q: %w

Error message

failed to read remote resource %q: %w

What it means

The HTTP request succeeded with a 2xx status, but reading the response body with `io.ReadAll` failed partway through. This indicates the connection was interrupted mid-transfer — the server closed early, a timeout expired during the read, or the response was truncated relative to its Content-Length.

Source

Thrown at resources/resource_factories/create/remote.go:298

			// 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 {
				filename = params["filename"]
			}
		}

		contentType := res.Header.Get("Content-Type")

		// For HEAD requests we have no body to work with, so we need to use the Content-Type header.
		if isHeadMethod || c.rs.ExecHelper.Sec().HTTP.MediaTypes.Accept(contentType) {
			var found bool
			mediaType, found = c.rs.MediaTypes().GetByType(contentType)
			if !found {
				// A media type not configured in Hugo, just create one from the content type string.

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Increase the timeout for that request: `dict "timeout" "120s"` (per-request) or raise `timeout` in site config.
  2. Retry the build — if it's transient network flakiness, the file cache will keep the successful result; consider a stable `key` option to control cache eviction.
  3. Test the download from the build environment with `curl -o /dev/null -w '%{size_download}' <url>` to confirm the server serves the full body reliably; switch to a more reliable mirror/CDN if not.

Example fix

{{/* before */}}
{{ $r := resources.GetRemote $bigFileURL }}
{{/* after */}}
{{ $r := resources.GetRemote $bigFileURL (dict "timeout" "120s") }}
Defensive patterns

Strategy: try-catch

Try / catch

{{ $r := resources.GetRemote $url }}
{{ with $r.Err }}
  {{ errorf "remote resource body read failed for %s: %s" $url . }}
{{ end }}

Prevention

When it happens

Trigger: `resources.GetRemote` downloading a large file when the per-request `timeout` (or global timeout) expires during body read (context deadline exceeded), the remote server or a proxy resetting the connection mid-stream, or gzip/chunked-encoding corruption from the origin.

Common situations: Fetching large assets (images, archives, big JSON) with the default or a short `timeout` on slow CI networks, flaky CDNs or proxies dropping long transfers, and corporate proxies interfering with chunked responses.

Related errors


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/45f1d3a798467783.json. Report an issue: GitHub ↗.