gohugoio/hugo · error

resource %T does not implement…

Error message

resource %T does not implement resource.ReadSeekerCloserResource

What it means

Returned by `bundler.Client.Concat` (bundler.go:120-126) when a resource in the input list does not implement `resource.ReadSeekCloserResource`. Concat needs to open each source as a `ReadSeekCloser` to stream bytes; resources that are pure metadata, page-less, or remote-without-seek cannot be concatenated. The type assertion at bundler.go:123-125 fails.

Solutions

  1. Filter the list to resources known to be readable (local file resources, `resources.FromString` outputs that are still seekable).
  2. For remote resources, fetch with GET (default) so the body is available for re-reading.
  3. If using a custom Resource type, implement `ReadSeekCloser() (hugio.ReadSeekCloser, error)`.
  4. Replace non-readable entries with a readable equivalent (e.g. re-fetch remote with GET).

Example fix

// template -- before
{{ $bundle := resources.Concat "out.js" (slice $headOnlyRemote $localJS) }}

// after
{{ $remote := resources.GetRemote "https://example.com/app.js" (dict "method" "GET") }}
{{ $bundle := resources.Concat "out.js" (slice $remote $localJS) }}
Defensive patterns

Strategy: type-guard

Type guard

func isReadable(v any) bool {
	_, ok := v.(resource.ReadSeekCloserResource)
	return ok
}

Prevention

When it happens

Trigger: Passing into `resources.Concat` a resource that is not a readable/seekable source -- e.g. a remote Resource created with method `HEAD` (no body), a Resource that wraps only metadata, a stub used for identity, or a third-party Resource type missing the `ReadSeekCloser()` method.

Common situations: Bundling remote resources fetched via `resources.GetRemote` with `method=HEAD`; mixing in resources produced by `resources.FromString` after they've been transformed to a non-seekable wrapper; custom Resource implementations registered by themes/plugins that skip the ReadSeekCloser interface; bugs where a transformed resource loses its reader capability.

Related errors


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

Appendix: source

Thrown at resources/resource_factories/bundler/bundler.go:125

				for _, rr := range r {
					identity.WalkIdentitiesShallow(rr, func(depth int, id identity.Identity) bool {
						terminate = f(id)
						return terminate
					})
					if terminate {
						break
					}
				}
				return terminate
			},
		))

		concatr := func() (hugio.ReadSeekCloser, error) {
			var rcsources []hugio.ReadSeekCloser
			for _, s := range r {
				rcr, ok := s.(resource.ReadSeekCloserResource)
				if !ok {
					return nil, fmt.Errorf("resource %T does not implement resource.ReadSeekerCloserResource", s)
				}
				rc, err := rcr.ReadSeekCloser()
				if err != nil {
					// Close the already opened.
					for _, rcs := range rcsources {
						rcs.Close()
					}
					return nil, err
				}

				rcsources = append(rcsources, rc)
			}

			// Arbitrary JavaScript files require a barrier between them to be safely concatenated together.
			// Without this, the last line of one file can affect the first line of the next file and change how both files are interpreted.
			if resolvedm.MainType == media.Builtin.JavascriptType.MainType && resolvedm.SubType == media.Builtin.JavascriptType.SubType {
				readers := make([]hugio.ReadSeekCloser, 2*len(rcsources)-1)
				j := 0

View on GitHub (pinned to 52c9bd7908)