From f797f84902297b7dd37c3f39ce057789a4d8e950 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Fri, 27 Feb 2026 10:21:12 +0100 Subject: [PATCH] Fix index out of range panic in fileEventsContentPaths The nested loop had dirs as the outer loop and others as the inner loop with a single counter, causing n to exceed len(others) when multiple dirs existed. Swap the loop order so each file in others is checked against all dirs exactly once. Fixes #14573 Co-Authored-By: Claude Opus 4.6 --- hugolib/integrationtest_builder.go | 9 +++++++++ hugolib/rebuild_test.go | 27 +++++++++++++++++++++++++++ hugolib/site.go | 17 ++++++++++------- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/hugolib/integrationtest_builder.go b/hugolib/integrationtest_builder.go index ed558cbaf..c08a86c47 100644 --- a/hugolib/integrationtest_builder.go +++ b/hugolib/integrationtest_builder.go @@ -751,6 +751,15 @@ func (s *IntegrationTestBuilder) AddFiles(filenameContent ...string) *Integratio return s } +func (s *IntegrationTestBuilder) CreateDirs(dirnames ...string) *IntegrationTestBuilder { + for _, dirname := range dirnames { + absDir := s.absFilename(filepath.FromSlash(dirname)) + s.Assert(s.fs.Source.MkdirAll(absDir, 0o777), qt.IsNil) + s.createdFiles = append(s.createdFiles, absDir) + } + return s +} + func (s *IntegrationTestBuilder) RemoveFiles(filenames ...string) *IntegrationTestBuilder { for _, filename := range filenames { absFilename := s.absFilename(filename) diff --git a/hugolib/rebuild_test.go b/hugolib/rebuild_test.go index afa8e326c..bf2c13a3c 100644 --- a/hugolib/rebuild_test.go +++ b/hugolib/rebuild_test.go @@ -399,6 +399,33 @@ func TestRebuilErrorRecovery(t *testing.T) { b.EditFileReplaceAll("content/mysection/mysectionbundle/index.md", "{{< foo }}", "{{< foo >}}").Build() } +// Issue 14573 +func TestRebuildAddContentWithMultipleDirCreations(t *testing.T) { + t.Parallel() + files := ` +-- hugo.toml -- +baseURL = "https://example.com" +disableLiveReload = true +-- content/p1.md -- +--- +title: "P1" +--- +-- layouts/page.html -- +Single: {{ .Title }}|{{ .Content }}| +-- layouts/list.html -- +Pages: {{ range .RegularPages }}{{ .RelPermalink }}|{{ end }}$ +` + b := TestRunning(t, files) + b.AssertFileContent("public/index.html", "Pages: /p1/|$") + b.AddFiles( + "content/nesteddir/dir1/post.md", "---\ntitle: Post\n---", + ).CreateDirs( + "content/dir1", + "content/dir2", + ).Build() + b.AssertFileContent("public/nesteddir/dir1/post/index.html", "Single: Post|") +} + func TestRebuildAddPageListPagesInHome(t *testing.T) { files := ` -- hugo.toml -- diff --git a/hugolib/site.go b/hugolib/site.go index 07fe41d2a..3ceccc440 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -1316,15 +1316,18 @@ func (h *HugoSites) fileEventsContentPaths(p []pathChange) []pathChange { // Remove all files below dir. if len(dirs) > 0 { n := 0 - for _, d := range dirs { - dir := d.p.Path() + "/" - for _, o := range others { - if !strings.HasPrefix(o.p.Path(), dir) { - others[n] = o - n++ + for _, o := range others { + keep := true + for _, d := range dirs { + if strings.HasPrefix(o.p.Path(), d.p.Path()+"/") { + keep = false + break } } - + if keep { + others[n] = o + n++ + } } others = others[:n] } -- 2.39.5