Repository: gohugoio/hugo (language: go)

Issue:
Hugo server crash when saving a partial used in content adapter
## Steps to reproduce (Hugo 126.1 on Windows 11)

* hugo new && hugo new theme
 
*  create `layouts/partials/gettitle.html`

   ```go
   {{ return "This will crash when saved" }} 
   ```
* create `content/_content.gotmpl`

   ```html
   {{ $title := partial "gettitle.html" }}
   {{ $content := dict "mediaType" "text/markdown" "value" "## Hello" }}
   {{ $page := dict "content" $content "title" $title "path" $title }}
   {{ $.AddPage $page }}
   ``` 

* fire up `hugo server`

* visit site to see the text headline at the bottom of the page 

*  edit `layouts/partials/gettitle.html`
   ```go
   {{ return "This will crash when saved - BOOM!" }} 
   ```
   in fact the change does not matter a simple blank or newline will do

```text
>>> hugo server
Watching for changes in C:\_repos\github\hugo-github-issue\{archetypes,assets,content,data,i18n,layouts,static,themes}
Watching for config changes in C:\_repos\github\hugo-github-issue\hugo.toml, C:\_repos\github\hugo-github-issue\themes\hugo\hugo.toml
Start building sites …
hugo v0.126.1-3d40aba512931031921463dafc172c0d124437b8+extended windows/amd64 BuildDate=2024-05-15T10:42:34Z VendorInfo=gohugoio


                   | EN
-------------------+-----
  Pages            | 19
  Paginator pages  |  0
  Non-page files   |  1
  Static files     |  1
  Processed images |  0
  Aliases          |  0
  Cleaned          |  0

Built in 14 ms
Environment: "development"
Serving pages from disk
Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
Press Ctrl+C to stop

Change detected, rebuilding site (#1).
2024-05-24 21:51:56.713 +0200
Template changed /partials/gettitle.html
Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
Total in 5 ms
panic: html/template: cannot Clone "" after it has executed

goroutine 23 [running]:
github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate.Must(...)
        /root/project/hugo/tpl/internal/go_templates/htmltemplate/template.go:369
github.com/gohugoio/hugo/tpl/tplimpl.(*templateNamespace).createPrototypes(0xc001227740)
        /root/project/hugo/tpl/tplimpl/template.go:985 +0xa9
github.com/gohugoio/hugo/tpl/tplimpl.(*templateExec).MarkReady.func1()
        /root/project/hugo/tpl/tplimpl/template.go:314 +0x3c
sync.(*Once).doSlow(0x21095f?, 0x286fb20?)
        /usr/local/go/src/sync/once.go:74 +0xc2
sync.(*Once).Do(...)
        /usr/local/go/src/sync/once.go:65
github.com/gohugoio/hugo/tpl/tplimpl.(*templateExec).MarkReady(0x2432e40?)
        /root/project/hugo/tpl/tplimpl/template.go:311 +0x59
github.com/gohugoio/hugo/hugolib.newHugoSites.func3({0x0?, 0xc0000580c0?})
        /root/project/hugo/hugolib/site_new.go:356 +0xab
github.com/gohugoio/hugo/lazy.(*Init).Do.func1()
        /root/project/hugo/lazy/init.go:107 +0xe2
github.com/gohugoio/hugo/lazy.(*onceMore).Do(0xc50403?, 0xc00004b110?)
        /root/project/hugo/lazy/once.go:53 +0x129
github.com/gohugoio/hugo/lazy.(*Init).Do(0xc00074b730, {0x4253308?, 0x55bcda0?})
        /root/project/hugo/lazy/init.go:88 +0x65
github.com/gohugoio/hugo/lazy.(*Init).Do.func1()
        /root/project/hugo/lazy/init.go:112 +0x18a
github.com/gohugoio/hugo/lazy.(*onceMore).Do(0x27f3ad?, 0x6650efdc?)
        /root/project/hugo/lazy/once.go:53 +0x129
github.com/gohugoio/hugo/lazy.(*Init).Do(0xc00074a690, {0x4253308?, 0x55bcda0?})
        /root/project/hugo/lazy/init.go:88 +0x65
github.com/gohugoio/hugo/hugolib.(*HugoSites).render(0xc000a34000, {0x425c2f0?, 0xc0000b0960?}, 0xc0013096c0)
        /root/project/hugo/hugolib/hugo_sites_build.go:327 +0x132
github.com/gohugoio/hugo/hugolib.(*HugoSites).Build(0xc000a34000, {0x0, 0x0, 0x0, 0x0, 0xc0008a0c60, 0x0, 0x1, 0x0}, {0xc00054b140, ...})
        /root/project/hugo/hugolib/hugo_sites_build.go:168 +0x77b
github.com/gohugoio/hugo/commands.(*hugoBuilder).rebuildSites(0xc00076f380, {0xc00054b140, 0x2, 0x2})
        /root/project/hugo/commands/hugobuilder.go:1019 +0x188
github.com/gohugoio/hugo/commands.(*hugoBuilder).handleEvents.func6(0xc00076f380, 0xc001790600)
        /root/project/hugo/commands/hugobuilder.go:864 +0x8b
github.com/gohugoio/hugo/commands.(*hugoBuilder).handleEvents(0xc00076f380, 0xc0001116b0, 0xc0007d01a8, {0xc001066f00, 0x2, 0x2}, 0xc000120570)
        /root/project/hugo/commands/hugobuilder.go:867 +0x13ba
github.com/gohugoio/hugo/commands.(*hugoBuilder).newWatcher.func2()
        /root/project/hugo/commands/hugobuilder.go:352 +0x25d
created by github.com/gohugoio/hugo/commands.(*hugoBuilder).newWatcher in goroutine 1
        /root/project/hugo/commands/hugobuilder.go:343 +0x4c5
```

### What version of Hugo are you using?

```
hugo v0.126.1-3d40aba512931031921463dafc172c0d124437b8+extended windows/amd64 BuildDate=2024-05-15T10:42:34Z VendorInfo=gohugoio
GOOS="windows"
GOARCH="amd64"
GOVERSION="go1.22.2"
github.com/sass/libsass="3.6.5"
github.com/webmproject/libwebp="v1.3.2"
```





Discussion / hints:
Did *not* crash on Windows 11 WSL2 
* Ubuntu 22.04.4 LTS
*  and openSUSE Tumbleweed VERSION_ID="20240407"
Reproducible on Linux.
## regarding WSL won't crash:

I tested this with being in the windows path mounted

```bash
cd /mnt/c/_repos/github/hugo-github-issue
hugo server
```
* The browser used does not run in WSL
* editing the code was done in WSL 

* With this setup the server does not crash, but also no change is displayed
* viewing the shortcode in WSL and Windows both shows the same content

=> looks like hugo server does not see the change from windows in the WSL context.

## being in a WSL folder ~/hugo-forum-issue

* copied the files to the WSL linux filesystem 
*  start hugo server
* browser running on windows
* editing the file

=> it crashes 

## Conclusion WSL

* normal WSL usage it crashes
  * same as in Windows and Linux (as tested by @jmooring 
* mixed access (WSL mounted filesystem)
  * no crash no update - I consider this as an unusual edge case
I cannot reproduce this on MacOS and we have a very similar (and passing on all platforms) integration test. I don't doubt that this is a real issue, but I'm just saying that it's hard for me to fix (yes, I have some VMs I can boot up, but that may take some ... days).
All ok. As workaround i just add the partial directly to a layout. Once it's ready I take it over to the adapter. 
If there's anything addinional you like me to test. Just drop me a note.
Never mind, I actually can reproduce it -- I just didn't follow the (excellent) issue description to the letter.

Fix patch:
diff --git a/hugolib/content_map.go b/hugolib/content_map.go
index 452bf8efa23..6ab945209ec 100644
--- a/hugolib/content_map.go
+++ b/hugolib/content_map.go
@@ -335,12 +335,6 @@ func (m *pageMap) addPagesFromGoTmplFi(fi hugofs.FileMetaInfo, buildConfig *Buil
 	f := source.NewFileInfo(fi)
 	h := s.h
 
-	// Make sure the layouts are initialized.
-	if _, err := h.init.layouts.Do(context.Background()); err != nil {
-		addErr = err
-		return
-	}
-
 	contentAdapter := s.pageMap.treePagesFromTemplateAdapters.Get(pi.Base())
 	var rebuild bool
 	if contentAdapter != nil {
diff --git a/hugolib/hugo_sites_build.go b/hugolib/hugo_sites_build.go
index 4bea9303957..8a4966055d8 100644
--- a/hugolib/hugo_sites_build.go
+++ b/hugolib/hugo_sites_build.go
@@ -239,6 +239,10 @@ func (h *HugoSites) process(ctx context.Context, l logg.LevelLogger, config *Bui
 	l = l.WithField("step", "process")
 	defer loggers.TimeTrackf(l, time.Now(), nil, "")
 
+	if _, err := h.init.layouts.Do(ctx); err != nil {
+		return err
+	}
+
 	if len(events) > 0 {
 		// This is a rebuild
 		return h.processPartial(ctx, l, config, init, events)
@@ -324,10 +328,6 @@ func (h *HugoSites) render(l logg.LevelLogger, config *BuildCfg) error {
 		loggers.TimeTrackf(l, start, h.buildCounters.loggFields(), "")
 	}()
 
-	if _, err := h.init.layouts.Do(context.Background()); err != nil {
-		return err
-	}
-
 	siteRenderContext := &siteRenderContext{cfg: config, multihost: h.Configs.IsMultihost}
 
 	i := 0
@@ -918,7 +918,6 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf
 	if tmplChanged || i18nChanged {
 		// TODO(bep) we should split this, but currently the loading of i18n and layout files are tied together. See #12048.
 		h.init.layouts.Reset()
-
 		if err := loggers.TimeTrackfn(func() (logg.LevelLogger, error) {
 			// TODO(bep) this could probably be optimized to somehow
 			// only load the changed templates and its dependencies, but that is non-trivial.
@@ -991,6 +990,10 @@ func (s *Site) handleContentAdapterChanges(bi pagesfromdata.BuildInfo, buildConf
 }
 
 func (h *HugoSites) processContentAdaptersOnRebuild(ctx context.Context, buildConfig *BuildCfg) error {
+	// Make sure the layouts are initialized.
+	if _, err := h.init.layouts.Do(context.Background()); err != nil {
+		return err
+	}
 	g := rungroup.Run[*pagesfromdata.PagesFromTemplate](ctx, rungroup.Config[*pagesfromdata.PagesFromTemplate]{
 		NumWorkers: h.numWorkers,
 		Handle: func(ctx context.Context, p *pagesfromdata.PagesFromTemplate) error {


Test patch:
diff --git a/hugolib/pagesfromdata/pagesfromgotmpl_integration_test.go b/hugolib/pagesfromdata/pagesfromgotmpl_integration_test.go
index 3a37c233b96..cbb2da75c86 100644
--- a/hugolib/pagesfromdata/pagesfromgotmpl_integration_test.go
+++ b/hugolib/pagesfromdata/pagesfromgotmpl_integration_test.go
@@ -38,7 +38,11 @@ draft: false
 -- layouts/partials/get-value.html --
 {{ $val := "p1" }}
 {{ return $val }}
+-- layouts/_default/baseof.html --
+Baseof:
+{{ block "main" . }}{{ end }}
 -- layouts/_default/single.html --
+{{ define "main" }}
 Single: {{ .Title }}|{{ .Content }}|Params: {{ .Params.param1 }}|Path: {{ .Path }}|
 Dates: Date: {{ .Date.Format "2006-01-02" }}|Lastmod: {{ .Lastmod.Format "2006-01-02" }}|PublishDate: {{ .PublishDate.Format "2006-01-02" }}|ExpiryDate: {{ .ExpiryDate.Format "2006-01-02" }}|
 Len Resources: {{ .Resources | len }}
@@ -49,6 +53,7 @@ Featured Image: {{ .RelPermalink }}|{{ .Name }}|
 Resized Featured Image: {{ .RelPermalink }}|{{ .Width }}|
 {{ end}}
 {{ end }}
+{{ end }}
 -- layouts/_default/list.html --
 List: {{ .Title }}|{{ .Content }}|
 RegularPagesRecursive: {{ range .RegularPagesRecursive }}{{ .Title }}:{{ .Path }}|{{ end }}$