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
- Check the pipeline order — only apply text/content transforms to text-like resources; move image transforms to the end of the chain.
- 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.
- Re-fetch the source with `resources.Get`/`resources.GetRemote` (checking `.Err`) so a readable resource enters the transform rather than a derived one.
- 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
- Only apply transforms (minify, fingerprint, postCSS) to resources obtained from resources.Get/GetMatch or page resources
- Don't feed page objects or plain strings into resource transform functions
- Use resources.FromString to wrap raw strings before transforming them
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
- failed to detect format from content
- failed to detect target data serialization format
- arguments to symdiff must be slices or arrays
- can't iterate over %T
- text must be a string
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/9fe5200689ebf8cd.json.
Report an issue: GitHub ↗.