{"record":{"id":"1028dae94ea2ba84","repo":"gohugoio/hugo","slug":"failed-to-marshal-params-w","errorCode":null,"errorMessage":"failed to marshal params: %w","messagePattern":"failed to marshal params: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/esbuild/resolve.go","lineNumber":355,"sourceCode":"\n\t\t\t\t\treturn api.OnLoadResult{\n\t\t\t\t\t\tResolveDir: opts.ResolveDir,\n\t\t\t\t\t\tContents:   &c,\n\t\t\t\t\t\tLoader:     opts.loaderFromFilename(args.Path),\n\t\t\t\t\t}, nil\n\t\t\t\t})\n\t\t},\n\t}\n\n\tparams := opts.Params\n\tif params == nil {\n\t\t// This way @params will always resolve to something.\n\t\tparams = make(map[string]any)\n\t}\n\n\tb, err := json.Marshal(params)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to marshal params: %w\", err)\n\t}\n\n\tparamsPlugin := api.Plugin{\n\t\tName: \"hugo-params-plugin\",\n\t\tSetup: func(build api.PluginBuild) {\n\t\t\tbuild.OnResolve(api.OnResolveOptions{Filter: `^@params(/config)?$`},\n\t\t\t\tfunc(args api.OnResolveArgs) (api.OnResolveResult, error) {\n\t\t\t\t\tresolvedPath := args.Importer\n\n\t\t\t\t\tif args.Path == pathHugoConfigParams {\n\t\t\t\t\t\tresolvedPath = pathHugoConfigParams\n\t\t\t\t\t}\n\n\t\t\t\t\treturn api.OnResolveResult{\n\t\t\t\t\t\tPath:      resolvedPath,\n\t\t\t\t\t\tNamespace: nsHugoParams,\n\t\t\t\t\t}, nil\n\t\t\t\t})","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/internal/js/esbuild/resolve.go#L337-L373","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n{{ $opts := dict \"params\" . }}\n\n// after\n{{ $opts := dict \"params\" (dict \"title\" .Title \"url\" .Permalink) }}","handlingStrategy":"validation","validationCode":"// Pre-marshal Params yourself so the json error surfaces with full context\n// before Build wraps it.\nif opts.Params != nil {\n    if _, err := json.Marshal(opts.Params); err != nil {\n        return fmt.Errorf(\"Params not JSON-serializable: %w\", err)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["esbuild","params","json","config"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}