gohugoio/hugo · error

cannot transform content of Resource of type %T

Error message

cannot transform content of Resource of type %T

What it means

Returned by contentReadSeekCloser when a resource being transformed does not implement resource.ReadSeekCloserResource. Transformations need a ReadSeeker to re-read content (e.g. for caching, integrity, multi-pass transforms); resources that only expose a one-shot reader cannot be transformed and hit the default branch with %T.

Solutions

  1. Ensure the resource is seekable — materialize it first (e.g. fetch and cache the remote resource, or copy into a resource that implements ReadSeekCloserResource).
  2. Use resources.Get followed by a clone/copy that supports ReadSeekCloser before transforming.
  3. If implementing a custom resource type, implement resource.ReadSeekCloserResource (ReadSeekCloser() method) so it can be transformed.

Example fix

// before
{{ $r := resources.GetRemote "https://example.com/style.css" }}
{{ $x := $r | minify }} // cannot transform content of Resource of type *remoteResource

// after
{{ $r := resources.GetRemote "https://example.com/style.css" | resources.Copy "style.css" }}
{{ $x := $r | minify }}
Defensive patterns

Strategy: type-guard

Validate before calling

// Guard that a resource is transformable (seekable) before transforming.
func isTransformable(r resource.Resource) bool {
    _, ok := r.(resource.ReadSeekCloserResource)
    return ok
}

Type guard

// Go type guard for ReadSeekCloserResource.
func asSeekable(r resource.Resource) (resource.ReadSeekCloserResource, bool) {
    s, ok := r.(resource.ReadSeekCloserResource)
    return s, ok
}

Prevention

When it happens

Trigger: Calling a transformation (TransformWithContext/Transform) on a resource type that does not implement ReadSeekCloserResource — for example a remote-only resource, a constructed resource without seek support, or a post-publish resource that wasn't wrapped with ReadSeekCloser capability.

Common situations: Passing a resource obtained from resources.GetRemote (without caching) into a transform that needs seek; wrapping a reader-only adapter as a resource; transforming a remote/headless bundle resource directly.

Related errors


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

Appendix: source

Thrown at resources/transform.go:837

// 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 52c9bd7908)