Repository: gohugoio/hugo (go)

Issue:
panic: recovered from errgroup.Group: assignment to entry in nil map
Up until v0.147.1 the build concludes with no issues, anything above that will present this error. I have tried troubleshooting but the error message doesn't quite make the culprit clear to me.

Tested on Void Linux and Alpine Linux.

- [Reference repository](https://git.sr.ht/~cujo/cujo.casa)
- [Failed build output](https://builds.sr.ht/~cujo/job/1514474)

```
Start building sites … 
hugo v0.147.7+extended linux/amd64 BuildDate=unknown

Total in 38 ms
panic: recovered from errgroup.Group: assignment to entry in nil map

goroutine 1 [running]:
golang.org/x/sync/errgroup.(*Group).Wait(0xc000880d80)
	/builddir/hugo-0.147.7/_build-hugo-xbps/pkg/mod/golang.org/x/sync@v0.14.0/errgroup/errgroup.go:70 +0x6d
github.com/gohugoio/hugo/hugolib.(*HugoSites).assemble(0xc00040cdc0, {0x249ed10, 0x3741c80}, {0x24a7250?, 0xc00007fe60?}, 0xc0005d6c80)
	/builddir/hugo-0.147.7/hugolib/hugo_sites_build.go:307 +0x40f
github.com/gohugoio/hugo/hugolib.(*HugoSites).Build.func4(...)
	/builddir/hugo-0.147.7/hugolib/hugo_sites_build.go:152
github.com/gohugoio/hugo/hugolib.(*HugoSites).Build(0xc00040cdc0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, {0x0, ...})
	/builddir/hugo-0.147.7/hugolib/hugo_sites_build.go:159 +0x74a
github.com/gohugoio/hugo/commands.(*hugoBuilder).buildSites(0xc0000dc0c0?, 0x0)
	/builddir/hugo-0.147.7/commands/hugobuilder.go:425 +0x10d
github.com/gohugoio/hugo/commands.(*hugoBuilder).fullBuild.func3(...)
	/builddir/hugo-0.147.7/commands/hugobuilder.go:542
github.com/gohugoio/hugo/commands.(*hugoBuilder).fullBuild(0xc000144f00, 0x0)
	/builddir/hugo-0.147.7/commands/hugobuilder.go:558 +0x3f2
github.com/gohugoio/hugo/commands.(*hugoBuilder).build(0xc000144f00)
	/builddir/hugo-0.147.7/commands/hugobuilder.go:397 +0x65
github.com/gohugoio/hugo/commands.(*rootCommand).Run.func1(0xc000144f00?, 0xc000641540?)
	/builddir/hugo-0.147.7/commands/commandeer.go:382 +0x86
github.com/gohugoio/hugo/commands.(*rootCommand).Run(0xc000231080, {0x0?, 0x0?}, 0xc000641540, {0x31f9ea854ea5a7e6?, 0xc0004c7a20?, 0x0?})
	/builddir/hugo-0.147.7/commands/commandeer.go:387 +0x134
github.com/bep/simplecobra.(*Commandeer).compile.func1(0xc0001c0f00?, {0x3741c80?, 0x4?, 0x1f64b04?})
	/builddir/hugo-0.147.7/_build-hugo-xbps/pkg/mod/github.com/bep/simplecobra@v0.6.0/simplecobra.go:113 +0x4c
github.com/spf13/cobra.(*Command).execute(0xc00013f508, {0xc00003e110, 0x0, 0x0})
	/builddir/hugo-0.147.7/_build-hugo-xbps/pkg/mod/github.com/spf13/cobra@v1.9.1/command.go:1015 +0xaaa
github.com/spf13/cobra.(*Command).ExecuteC(0xc00013f508)
	/builddir/hugo-0.147.7/_build-hugo-xbps/pkg/mod/github.com/spf13/cobra@v1.9.1/command.go:1148 +0x46f
github.com/spf13/cobra.(*Command).ExecuteContextC(...)
	/builddir/hugo-0.147.7/_build-hugo-xbps/pkg/mod/github.com/spf13/cobra@v1.9.1/command.go:1080
github.com/bep/simplecobra.(*Exec).Execute(0xc00006ecb8, {0x249ed10?, 0x3741c80?}, {0xc00003e110?, 0xc000002301?, 0xc00006a688?})
	/builddir/hugo-0.147.7/_build-hugo-xbps/pkg/mod/github.com/bep/simplecobra@v0.6.0/simplecobra.go:155 +0xd4
github.com/gohugoio/hugo/commands.Execute({0xc00003e110, 0x0, 0x0})
	/builddir/hugo-0.147.7/commands/commandeer.go:68 +0x2f3
main.main()
	/builddir/hugo-0.147.7/main.go:25 +0x56
```

### What version of Hugo are you using (`hugo version`)?

<pre>
$ hugo version
hugo v0.147.7+extended linux/amd64 BuildDate=unknown
</pre>

### Does this issue reproduce with the latest release?

Yes

Pull request:
resources/page: Make sure a map is always initialized
Fixes #13810


Patch:
diff --git a/resources/page/page_matcher.go b/resources/page/page_matcher.go
index 306c2d03c..858def5ef 100644
--- a/resources/page/page_matcher.go
+++ b/resources/page/page_matcher.go
@@ -174,6 +174,9 @@ func DecodeCascade(logger loggers.Logger, handleLegacyFormat bool, in any) (*map
 
 func mapToPageMatcherParamsConfig(m map[string]any) (PageMatcherParamsConfig, error) {
 	var pcfg PageMatcherParamsConfig
+	if pcfg.Fields == nil {
+		pcfg.Fields = make(maps.Params)
+	}
 	for k, v := range m {
 		switch strings.ToLower(k) {
 		case "_target", "target":
@@ -193,9 +196,6 @@ func mapToPageMatcherParamsConfig(m map[string]any) (PageMatcherParamsConfig, er
 				}
 			}
 		default:
-			if pcfg.Fields == nil {
-				pcfg.Fields = make(maps.Params)
-			}
 
 			pcfg.Fields[k] = v
 		}


Test patch:
diff --git a/resources/page/page_matcher_test.go b/resources/page/page_matcher_test.go
index ad35da43c..7f441d3ab 100644
--- a/resources/page/page_matcher_test.go
+++ b/resources/page/page_matcher_test.go
@@ -99,6 +99,7 @@ func TestPageMatcher(t *testing.T) {
 			Params: maps.Params{
 				"foo": "bar",
 			},
+			Fields: maps.Params{},
 			Target: PageMatcher{Path: "", Kind: "page", Lang: "", Environment: ""},
 		})
 	})
@@ -136,9 +137,10 @@ func TestDecodeCascadeConfig(t *testing.T) {
 	c.Assert(got.SourceStructure, qt.DeepEquals, []PageMatcherParamsConfig{
 		{
 			Params: maps.Params{"a": string("av")},
+			Fields: maps.Params{},
 			Target: PageMatcher{Kind: "page", Environment: "production"},
 		},
-		{Params: maps.Params{"b": string("bv")}, Target: PageMatcher{Kind: "page"}},
+		{Params: maps.Params{"b": string("bv")}, Fields: maps.Params{}, Target: PageMatcher{Kind: "page"}},
 	})
 
 	got, err = DecodeCascadeConfig(loggers.NewDefault(), true, nil)
diff --git a/tpl/tplimpl/templatestore.go b/tpl/tplimpl/templatestore.go
index bbb7f27cc..23c821cac 100644
--- a/tpl/tplimpl/templatestore.go
+++ b/tpl/tplimpl/templatestore.go
@@ -1018,7 +1018,7 @@ func (s *TemplateStore) allRawTemplates() iter.Seq[tpl.Template] {
 }
 
 func (s *TemplateStore) insertEmbedded() error {
-	return fs.WalkDir(embeddedTemplatesFs, ".", func(path string, d fs.DirEntry, err error) error {
+	return fs.WalkDir(embeddedTemplatesFs, ".", func(tpath string, d fs.DirEntry, err error) error {
 		if err != nil {
 			return err
 		}
@@ -1026,7 +1026,7 @@ func (s *TemplateStore) insertEmbedded() error {
 			return nil
 		}
 
-		templb, err := embeddedTemplatesFs.ReadFile(path)
+		templb, err := embeddedTemplatesFs.ReadFile(tpath)
 		if err != nil {
 			return err
 		}
@@ -1034,7 +1034,7 @@ func (s *TemplateStore) insertEmbedded() error {
 		// Get the newlines on Windows in line with how we had it back when we used Go Generate
 		// to write the templates to Go files.
 		templ := string(bytes.ReplaceAll(templb, []byte("\r\n"), []byte("\n")))
-		name := strings.TrimPrefix(filepath.ToSlash(path), "embedded/templates/")
+		name := strings.TrimPrefix(filepath.ToSlash(tpath), "embedded/templates/")
 
 		insertOne := func(name, content string) error {
 			pi := s.opts.PathParser.Parse(files.ComponentFolderLayouts, name)
@@ -1064,6 +1064,19 @@ func (s *TemplateStore) insertEmbedded() error {
 			return nil
 		}
 
+		// Copy the embedded HTML table render hook to each output format.
+		// See https://github.com/gohugoio/hugo/issues/13351.
+		if name == path.Join(containerMarkup, "render-table.html") {
+			for _, of := range s.opts.OutputFormats {
+				path := paths.TrimExt(name) + "." + of.Name + of.MediaType.FirstSuffix.FullSuffix
+				if err := insertOne(path, templ); err != nil {
+					return err
+				}
+			}
+
+			return nil
+		}
+
 		if err := insertOne(name, templ); err != nil {
 			return err
 		}
diff --git a/tpl/tplimpl/templatestore_integration_test.go b/tpl/tplimpl/templatestore_integration_test.go
index 0b3ce7a56..9da959350 100644
--- a/tpl/tplimpl/templatestore_integration_test.go
+++ b/tpl/tplimpl/templatestore_integration_test.go
@@ -1508,3 +1508,43 @@ mytexts|safeHTML: {{ partial "mytext.txt" . | safeHTML }}
 		"mytexts|safeHTML: <div>mytext</div>",
 	)
 }
+
+func TestIssue13351(t *testing.T) {
+	t.Parallel()
+
+	files := `
+-- hugo.toml --
+disableKinds = ['page','rss','section','sitemap','taxonomy','term']
+[outputs]
+home = ['html','json']
+[outputFormats.html]
+weight = 1
+[outputFormats.json]
+weight = 2
+-- content/_index.md --
+---
+title: home
+---
+a|b
+:--|:--
+1|2
+-- layouts/index.html --
+{{ .Content }}
+-- layouts/index.json --
+{{ .Content }}
+`
+
+	b := hugolib.Test(t, files)
+	b.AssertFileContent("public/index.html", "<table>")
+	b.AssertFileContent("public/index.json", "<table>")
+
+	f := strings.ReplaceAll(files, "weight = 1", "weight = 0")
+	b = hugolib.Test(t, f)
+	b.AssertFileContent("public/index.html", "<table>")
+	b.AssertFileContent("public/index.json", "<table>")
+
+	f = strings.ReplaceAll(files, "weight = 1", "")
+	b = hugolib.Test(t, f)
+	b.AssertFileContent("public/index.html", "<table>")
+	b.AssertFileContent("public/index.json", "<table>")
+}