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
- Filter the list to resources known to be readable (local file resources, `resources.FromString` outputs that are still seekable).
- For remote resources, fetch with GET (default) so the body is available for re-reading.
- If using a custom Resource type, implement `ReadSeekCloser() (hugio.ReadSeekCloser, error)`.
- 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
- Only concat resources that have a readable body (local files, GET-fetched remotes, FromString outputs).
- Avoid HEAD-fetched remote resources in bundles.
- Implement `ReadSeekCloser()` on custom Resource types.
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
- resources in Concat must be of the same Media Type, got
- expected slice of Resource objects, received %T instead
- invalid slice type %T
- must provide one or more Resource objects to concat
- %T cannot be merged by language
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 := 0View on GitHub (pinned to 52c9bd7908)