gohugoio/hugo · error
failed to create resource for path
Error message
failed to create resource for path %q, expected a resource.Resource, got %T
What it means
Returned by Spec.NewResourceWrapperFromResourceConfig when the ResourceConfig.Content.Value is not a resource.Resource. The function type-switches on content.Value expecting an already-constructed resource.Resource; any other concrete type falls into the default branch and is reported via %T. This is an internal contract violation in how a ResourceConfig is assembled, not normally user-facing.
Solutions
- If you are calling NewResourceWrapperFromResourceConfig directly, ensure rc.Content.Value is a resource.Resource (e.g. produced by Spec.NewResource or resources.NewPointerResource) before calling it.
- If this surfaces from a normal build, file a Hugo issue with the stack trace and the offending rc.PathInfo; it indicates an internal contract break rather than a config mistake.
- Upgrade Hugo to the latest release; this is frequently fixed by an upstream patch since it is an internal invariant.
Example fix
// before
rc := &pagemeta.ResourceConfig{PathInfo: pi}
rc.Content.Value = []byte(rawBytes) // wrong type
// after
res, _ := spec.NewResource(descriptor) // returns resource.Resource
rc.Content.Value = res Defensive patterns
Strategy: type-guard
Validate before calling
// Before constructing a ResourceConfig, assert the value type.
func isResource(v any) bool {
_, ok := v.(resource.Resource)
return ok
}
if !isResource(rc.Content.Value) {
return fmt.Errorf("Content.Value must be resource.Resource, got %T", rc.Content.Value)
} Type guard
// Go type guard for resource.Resource.
func asResource(v any) (resource.Resource, bool) {
r, ok := v.(resource.Resource)
return r, ok
} Prevention
- When building ResourceConfig programmatically, always wrap content via Spec.NewResource.
- Add internal tests asserting NewResourceWrapperFromResourceConfig only receives resource.Resource values.
- Treat this error as an upstream bug if encountered in a normal build; pin a known-good Hugo version.
When it happens
Trigger: Internal code path constructs a *pagemeta.ResourceConfig whose Content.Value is set to a plain string, []byte, os.File, or a custom type instead of a resource.Resource, then calls NewResourceWrapperFromResourceConfig. Typically reached via page resource parsing or the resources.FromString pipeline when a downstream caller mis-wraps the content.
Common situations: A Hugo internal refactor or third-party module/hook that builds ResourceConfig objects and forgets to wrap raw content in a resource.ResourceLink / resource clone. End users almost never see this unless they are calling the resources package directly or hit a regression.
Related errors
- cannot transform content of Resource of type %T
- contentNodeToContentNodesPage: unexpected type %T
- DeleteFunc: unknown type %T
- failed to add internal partial decorator template
- failed to calculate hash for IntSets
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/c4feffaa6cf1cd24.
Report an issue: GitHub.
Appendix: source
Thrown at resources/resource_spec.go:169
FileCaches filecache.Caches
// Assets used after the build is done.
// This is shared between all sites.
*PostBuildAssets
}
type PostBuildAssets struct {
PostProcessResources *maphelpers.ConcurrentMap[string, postpub.PostPublishedResource]
JSConfigBuilder *jsconfig.Builder
}
func (r *Spec) NewResourceWrapperFromResourceConfig(rc *pagemeta.ResourceConfig) (resource.Resource, error) {
content := rc.Content
switch r := content.Value.(type) {
case resource.Resource:
return cloneWithMetadataFromResourceConfigIfNeeded(rc, r), nil
default:
return nil, fmt.Errorf("failed to create resource for path %q, expected a resource.Resource, got %T", rc.PathInfo.Path(), content.Value)
}
}
// NewResource creates a new Resource from the given ResourceSourceDescriptor.
func (r *Spec) NewResource(rd ResourceSourceDescriptor) (resource.Resource, error) {
if err := rd.init(r); err != nil {
return nil, err
}
dir, name := path.Split(rd.TargetPath)
dir = paths.ToSlashPreserveLeading(dir)
if dir == "/" {
dir = ""
}
rp := internal.ResourcePaths{
File: name,
Dir: dir,
BaseDirTarget: rd.BasePathTargetPath,View on GitHub (pinned to 52c9bd7908)