gohugoio/hugo · error

failed to resolve media type for remote resource

Error message

failed to resolve media type for remote resource %q

What it means

Returned by `Client.FromRemote` (remote.go:347-350) when, after exhausting every resolution path -- `Content-Type` header lookup in configured MediaTypes, `media.FromString`, file-extension hints, and content-based detection via `media.FromContent` -- the media type is still zero. Hugo refuses to create a Resource without a known media type because downstream pipelines (target path, suffix, transforms) all depend on it.

Solutions

  1. Add the `Content-Type` server-side, or have the endpoint return one.
  2. Provide a URL with a clear file extension (e.g. append `?format=json` is not enough -- use a real path component).
  3. Allow the relevant media type in `security.http.mediaTypes` config.
  4. If the body is real but untyped, save it locally and create the resource with `resources.FromString`/`resources.Get` plus explicit `MediaType`.
  5. Confirm the response is non-empty (an empty 200 body defeats content sniffing).

Example fix

// hugo.toml -- before
[security.http.mediaTypes]
allowed = []

// after
[security.http.mediaTypes]
allowed = ["application/json"]
Defensive patterns

Strategy: validation

Validate before calling

// Probe Content-Type before relying on the resource.
import (
	"net/http"
)
func probeContentType(url string) (string, error) {
	resp, err := http.Head(url)
	if err != nil { return "", err }
	return resp.Header.Get("Content-Type"), nil
}

Try / catch

// Fallback: fetch bytes, write locally, create typed resource.
if r, err := resources.GetRemote(url); err != nil {
	if strings.Contains(err.Error(), "failed to resolve media type") {
		body := fetchBytes(url)
		return resources.FromString("fetched.bin", string(body)), nil
	}
}

Prevention

When it happens

Trigger: Remote response has no `Content-Type` header, the URL has no recognizable file extension, and the body content is ambiguous or empty (so `media.FromContent` cannot classify). Also when the `Content-Type` is set but not in the allowed `security.http.mediaTypes` set and content sniffing also fails.

Common situations: Fetching JSON from an endpoint that returns no Content-Type and a body shorter than sniff thresholds; fetching binary blobs with generic `application/octet-stream` excluded by security policy; fetching from a server that returns 200 with empty body; misconfigured `mediaTypes` in hugo.toml so a valid type string isn't recognized; CDN stripping Content-Type.

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/056d5d92ef7ed245. Report an issue: GitHub.

Appendix: source

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

				if exts != nil {
					extensionHints = exts
				}
			}

			// Look for a file extension. If it's .txt, look for a more specific.
			if extensionHints == nil || extensionHints[0] == ".txt" {
				if ext := path.Ext(filename); ext != "" {
					extensionHints = []string{ext}
				}
			}

			// Now resolve the media type primarily using the content.
			mediaType = media.FromContent(c.rs.MediaTypes(), extensionHints, body)

		}

		if mediaType.IsZero() {
			return nil, fmt.Errorf("failed to resolve media type for remote resource %q", uri)
		}

		userKey = filename[:len(filename)-len(path.Ext(filename))] + "_" + userKey + mediaType.FirstSuffix.FullSuffix
		data := responseToData(res, false, options.ResponseHeaders)

		return c.rs.NewResource(
			resources.ResourceSourceDescriptor{
				MediaType:     mediaType,
				Data:          data,
				GroupIdentity: identity.StringIdentity(optionsKey),
				LazyPublish:   true,
				OpenReadSeekCloser: func() (hugio.ReadSeekCloser, error) {
					return hugio.NewReadSeekerNoOpCloser(bytes.NewReader(body)), nil
				},
				TargetPath: userKey,
			})
	})
}

View on GitHub (pinned to 52c9bd7908)