gohugoio/hugo · error
failed to marshal params: %w
Error message
failed to marshal params: %w
What it means
Returned when json.Marshal(params) fails while preparing the @params virtual module for the esbuild params plugin. The wrapped error is the json package's error and identifies the offending field.
Source
Thrown at internal/js/esbuild/resolve.go:355
return api.OnLoadResult{
ResolveDir: opts.ResolveDir,
Contents: &c,
Loader: opts.loaderFromFilename(args.Path),
}, nil
})
},
}
params := opts.Params
if params == nil {
// This way @params will always resolve to something.
params = make(map[string]any)
}
b, err := json.Marshal(params)
if err != nil {
return nil, fmt.Errorf("failed to marshal params: %w", err)
}
paramsPlugin := api.Plugin{
Name: "hugo-params-plugin",
Setup: func(build api.PluginBuild) {
build.OnResolve(api.OnResolveOptions{Filter: `^@params(/config)?$`},
func(args api.OnResolveArgs) (api.OnResolveResult, error) {
resolvedPath := args.Importer
if args.Path == pathHugoConfigParams {
resolvedPath = pathHugoConfigParams
}
return api.OnResolveResult{
Path: resolvedPath,
Namespace: nsHugoParams,
}, nil
})View on GitHub (pinned to 52c9bd7908)
Solutions
- Reduce Params to plain JSON-friendly types (string, number, bool, slice, map).
- Inspect the wrapped error for the offending field name/type.
- Avoid passing Hugo Page/Resource objects; pass primitive values derived from them.
Example fix
// before
{{ $opts := dict "params" . }}
// after
{{ $opts := dict "params" (dict "title" .Title "url" .Permalink) }} Defensive patterns
Strategy: validation
Validate before calling
// Pre-marshal Params yourself so the json error surfaces with full context
// before Build wraps it.
if opts.Params != nil {
if _, err := json.Marshal(opts.Params); err != nil {
return fmt.Errorf("Params not JSON-serializable: %w", err)
}
} Prevention
- Only pass JSON-serializable types in Params (string, number, bool, slice, map).
- Never pass complex Hugo objects (Page, Resource, Site) directly; extract primitives first.
- Pre-marshal Params in tests to catch regressions early.
When it happens
Trigger: The Params option contains a value that isn't JSON-serializable: funcs, channels, cyclic structures, or a struct with unexported fields and no custom Marshaler. The marshal at resolve.go:353 fails.
Common situations: User passes a Hugo object (Page, Resource, Site) directly as Params; templating constructs that include non-marshallable Go values; mapstructure decoding produces a map containing a type json.Marshal rejects.
Related errors
- failed to unmarshal config for path %q: %w
- front matter field %q must be a map: %w
- inject: absolute paths not supported, must be relative to /a
- inject: file %q not found
- failed to decode $_hugo_config in template: %w
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/1028dae94ea2ba84.
Report an issue: GitHub.