gohugoio/hugo · error

cannot transform content of Resource of type %T

Error message

cannot transform content of Resource of type %T

What it means

`contentReadSeekerCloser` in resources/transform.go opens a resource's bytes for a transformation step. It only handles resources implementing `resource.ReadSeekCloserResource`; anything else cannot have its content read, so the transformation is refused with the concrete type in `%T`. Image resources produced by certain pipelines and some wrapper/remote types don't implement this interface.

Source

Thrown at resources/transform.go:836

// We will persist this information to disk.
type transformedResourceMetadata struct {
	Target     string         `json:"Target"`
	MediaTypeV string         `json:"MediaType"`
	MetaData   map[string]any `json:"Data"`
}

// contentReadSeekerCloser returns a ReadSeekerCloser if possible for a given Resource.
func contentReadSeekerCloser(r resource.Resource) (hugio.ReadSeekCloser, error) {
	switch rr := r.(type) {
	case resource.ReadSeekCloserResource:
		rc, err := rr.ReadSeekCloser()
		if err != nil {
			return nil, err
		}
		return rc, nil
	default:
		return nil, fmt.Errorf("cannot transform content of Resource of type %T", r)

	}
}

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Check the pipeline order — only apply text/content transforms to text-like resources; move image transforms to the end of the chain.
  2. Inspect the `%T` in the message to identify which concrete resource type entered the transform, then trace back to where it was created in your templates.
  3. Re-fetch the source with `resources.Get`/`resources.GetRemote` (checking `.Err`) so a readable resource enters the transform rather than a derived one.
  4. If you own the resource type in a Go module, implement `resource.ReadSeekCloserResource` so it can participate in content transforms.

Example fix

{{/* before — image result piped into a text transform */}}
{{ $r := resources.Get "img/logo.png" | images.Resize "200x" | minify }}

{{/* after */}}
{{ $r := resources.Get "img/logo.png" | images.Resize "200x" }}
Defensive patterns

Strategy: type-guard

Validate before calling

// only pipe transformable resources into resources.Minify/PostCSS/etc.
{{ $r := resources.Get "css/main.css" }}
{{ if $r }}{{ $r = $r | minify }}{{ end }}

Type guard

// template-level guard: check the resource came from the asset pipeline
{{ if and $r (ne $r.ResourceType "") }}...{{ end }}

Prevention

When it happens

Trigger: Chaining a content-level transform — `resources.Minify`, `css.Sass`/`css.PostCSS`, `js.Build`, `resources.ExecuteAsTemplate`, `| replaceRE` style transforms — onto a resource whose concrete type isn't readable, e.g. the output of an image transform, a resource constructed by a custom module, or a resource wrapper created from front matter metadata.

Common situations: Piping an image resource (`.Resize`, `.Fill`) into a text transform by mistake; applying `resources.ExecuteAsTemplate` to a resource from `resources.GetRemote` that failed and returned an unexpected type; custom Go modules implementing `resource.Resource` without `ReadSeekCloser`.

Related errors


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