Repository: gohugoio/hugo (language: go)

Issue:
Duplicate target paths warning after upgrade to v0.115.0
### What version of Hugo are you using (`hugo version`)?

```sh
$ hugo version
hugo v0.115.0+extended linux/amd64 BuildDate=unknown
```

### Does this issue reproduce with the latest release?
Yes
---
After upgrading from v0.114.1 to the latest version, I receive duplicate path warning for every content file every time I change, and save a file.

Steps to reproduce:
1. Clone/download the repo [xeptore/blog](https://github.com/xeptore/blog)
    ```sh
    curl -sSfL https://github.com/xeptore/blog/archive/main.tar.gz | tar -xzvf -
    ```
6. Install dependencies using `pnpm` (`pnpm install`)
7. Start server: `make run`
8. Edit, and save a random content file, e.g., `layouts/404.html`

If you follow the above steps having hugo version 0.114.1, no path warnings will be printed in the terminal. But,  if you upgrade the hugo version to v0.115.0, and try step 4, a duplicate target path warning will be printed similar to the following:
```txt
WARN  Duplicate target paths: /404.html (2), /about/index.html (2), /contact/index.html (2), /emoji-support-demo/index.html (2), /index.html (2), /index.xml (2), /markdown-syntax-guide/index.html (2), /math-typesetting-demo/index.html (2), /my-first-post-with-slug/index.html (2), /rich-content-demo/index.html (2), /sitemap.xml (2), /tags/demo/index.html (2), /tags/demo/index.xml (2), /tags/development/index.html (2), /tags/development/index.xml (2), /tags/emoji/index.html (2), /tags/emoji/index.xml (2), /tags/first/index.html (2), /tags/first/index.xml (2), /tags/hello/index.html (2), /tags/hello/index.xml (2), /tags/markdown/index.html (2), /tags/markdown/index.xml (2), /tags/privacy/index.html (2), /tags/privacy/index.xml (2), /tags/shortcodes/index.html (2), /tags/shortcodes/index.xml (2), pages/1/index.html (2), robots.txt (2), tags/demo/pages/1/index.html (2), tags/development/pages/1/index.html (2), tags/emoji/pages/1/index.html (2), tags/first/pages/1/index.html (2), tags/hello/pages/1/index.html (2), tags/markdown/pages/1/index.html (2), tags/privacy/pages/1/index.html (2), tags/shortcodes/pages/1/index.html (2)
```


Discussion / hints:
This is a side effect of the fix for fa0e16f4c79a703d122f1e3a3a99f4b779aea9b2 

We will fix this, but to me it does not make sense to have this enabled when running the server, so I suggest you at least temporarily turn it off in your server setup (or config) and just do `hugo --printPathWarnings` when you need to do these checks.



Fix patch:
diff --git a/commands/commandeer.go b/commands/commandeer.go
index 26bd25c0170..1a4ecf64f4f 100644
--- a/commands/commandeer.go
+++ b/commands/commandeer.go
@@ -110,12 +110,10 @@ type rootCommand struct {
 	environment string
 
 	// Common build flags.
-	baseURL              string
-	gc                   bool
-	poll                 string
-	forceSyncStatic      bool
-	printPathWarnings    bool
-	printUnusedTemplates bool
+	baseURL         string
+	gc              bool
+	poll            string
+	forceSyncStatic bool
 
 	// Profile flags (for debugging of performance problems)
 	cpuprofile   string
@@ -288,7 +286,7 @@ func (r *rootCommand) ConfigFromProvider(key int32, cfg config.Provider) (*commo
 			htime.Clock = clock.Start(configs.Base.C.Clock)
 		}
 
-		if base.LogPathWarnings {
+		if base.PrintPathWarnings {
 			// Note that we only care about the "dynamic creates" here,
 			// so skip the static fs.
 			fs.PublishDir = hugofs.NewCreateCountingFs(fs.PublishDir)
@@ -544,8 +542,8 @@ func applyLocalFlagsBuild(cmd *cobra.Command, r *rootCommand) {
 	cmd.Flags().BoolP("noChmod", "", false, "don't sync permission mode of files")
 	cmd.Flags().BoolP("noBuildLock", "", false, "don't create .hugo_build.lock file")
 	cmd.Flags().BoolP("printI18nWarnings", "", false, "print missing translations")
-	cmd.Flags().BoolVarP(&r.printPathWarnings, "printPathWarnings", "", false, "print warnings on duplicate target paths etc.")
-	cmd.Flags().BoolVarP(&r.printUnusedTemplates, "printUnusedTemplates", "", false, "print warnings on unused templates.")
+	cmd.Flags().BoolP("printPathWarnings", "", false, "print warnings on duplicate target paths etc.")
+	cmd.Flags().BoolP("printUnusedTemplates", "", false, "print warnings on unused templates.")
 	cmd.Flags().StringVarP(&r.cpuprofile, "profile-cpu", "", "", "write cpu profile to `file`")
 	cmd.Flags().StringVarP(&r.memprofile, "profile-mem", "", "", "write memory profile to `file`")
 	cmd.Flags().BoolVarP(&r.printm, "printMemoryUsage", "", false, "print memory usage to screen at intervals")
diff --git a/commands/helpers.go b/commands/helpers.go
index c342ce2c793..5021221fb00 100644
--- a/commands/helpers.go
+++ b/commands/helpers.go
@@ -79,11 +79,9 @@ func flagsToCfgWithAdditionalConfigBase(cd *simplecobra.Commandeer, cfg config.P
 
 	// Flags with a different name in the config.
 	keyMap := map[string]string{
-		"minify":            "minifyOutput",
-		"destination":       "publishDir",
-		"printI18nWarnings": "logI18nWarnings",
-		"printPathWarnings": "logPathWarnings",
-		"editor":            "newContentEditor",
+		"minify":      "minifyOutput",
+		"destination": "publishDir",
+		"editor":      "newContentEditor",
 	}
 
 	// Flags that we for some reason don't want to expose in the site config.
diff --git a/commands/hugobuilder.go b/commands/hugobuilder.go
index 3e96bfc73d6..b5cd0c2bbed 100644
--- a/commands/hugobuilder.go
+++ b/commands/hugobuilder.go
@@ -43,7 +43,6 @@ import (
 	"github.com/gohugoio/hugo/hugolib/filesystems"
 	"github.com/gohugoio/hugo/livereload"
 	"github.com/gohugoio/hugo/resources/page"
-	"github.com/gohugoio/hugo/tpl"
 	"github.com/gohugoio/hugo/watcher"
 	"github.com/spf13/fsync"
 	"golang.org/x/sync/errgroup"
@@ -418,13 +417,6 @@ func (c *hugoBuilder) build() error {
 			return err
 		}
 
-		if c.r.printUnusedTemplates {
-			unusedTemplates := h.Tmpl().(tpl.UnusedTemplatesProvider).UnusedTemplates()
-			for _, unusedTemplate := range unusedTemplates {
-				c.r.logger.Warnf("Template %s is unused, source file %s", unusedTemplate.Name(), unusedTemplate.Filename())
-			}
-		}
-
 		h.PrintProcessingStats(os.Stdout)
 		c.r.Println()
 	}
diff --git a/config/allconfig/allconfig.go b/config/allconfig/allconfig.go
index 2dc409be77d..bab15501b7e 100644
--- a/config/allconfig/allconfig.go
+++ b/config/allconfig/allconfig.go
@@ -484,12 +484,6 @@ type RootConfig struct {
 	// Enable to print greppable placeholders (on the form "[i18n] TRANSLATIONID") for missing translation strings.
 	EnableMissingTranslationPlaceholders bool
 
-	// Enable to print warnings for missing translation strings.
-	LogI18nWarnings bool
-
-	// ENable to print warnings for multiple files published to the same destination.
-	LogPathWarnings bool
-
 	// Enable to panic on warning log entries. This may make it easier to detect the source.
 	PanicOnWarning bool
 
@@ -525,6 +519,12 @@ type RootConfig struct {
 	// Whether to track and print unused templates during the build.
 	PrintUnusedTemplates bool
 
+	// Enable to print warnings for missing translation strings.
+	PrintI18nWarnings bool
+
+	// ENable to print warnings for multiple files published to the same destination.
+	PrintPathWarnings bool
+
 	// URL to be used as a placeholder when a page reference cannot be found in ref or relref. Is used as-is.
 	RefLinksNotFoundURL string
 
diff --git a/config/allconfig/configlanguage.go b/config/allconfig/configlanguage.go
index 95c5c7edfbc..be549126bd2 100644
--- a/config/allconfig/configlanguage.go
+++ b/config/allconfig/configlanguage.go
@@ -199,8 +199,8 @@ func (c ConfigLanguage) EnableMissingTranslationPlaceholders() bool {
 	return c.config.EnableMissingTranslationPlaceholders
 }
 
-func (c ConfigLanguage) LogI18nWarnings() bool {
-	return c.config.LogI18nWarnings
+func (c ConfigLanguage) PrintI18nWarnings() bool {
+	return c.config.PrintI18nWarnings
 }
 
 func (c ConfigLanguage) CreateTitle(s string) string {
diff --git a/config/allconfig/load.go b/config/allconfig/load.go
index 4e5478c408d..b9bb38aaf40 100644
--- a/config/allconfig/load.go
+++ b/config/allconfig/load.go
@@ -139,7 +139,11 @@ type configLoader struct {
 
 // Handle some legacy values.
 func (l configLoader) applyConfigAliases() error {
-	aliases := []types.KeyValueStr{{Key: "taxonomies", Value: "indexes"}}
+	aliases := []types.KeyValueStr{
+		{Key: "indexes", Value: "taxonomies"},
+		{Key: "logI18nWarnings", Value: "printI18nWarnings"},
+		{Key: "logPathWarnings", Value: "printPathWarnings"},
+	}
 
 	for _, alias := range aliases {
 		if l.cfg.IsSet(alias.Key) {
diff --git a/config/configProvider.go b/config/configProvider.go
index 8ed0728bd8a..5d6acce9f3b 100644
--- a/config/configProvider.go
+++ b/config/configProvider.go
@@ -57,7 +57,7 @@ type AllProvider interface {
 	EnableMissingTranslationPlaceholders() bool
 	TemplateMetrics() bool
 	TemplateMetricsHints() bool
-	LogI18nWarnings() bool
+	PrintI18nWarnings() bool
 	CreateTitle(s string) string
 	IgnoreFile(s string) bool
 	NewContentEditor() string
diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go
index 6ffef6fa880..9c121f7ac11 100644
--- a/hugolib/hugo_sites.go
+++ b/hugolib/hugo_sites.go
@@ -77,6 +77,8 @@ type HugoSites struct {
 	contentInit sync.Once
 	content     *pageMaps
 
+	postRenderInit sync.Once
+
 	// Keeps track of bundle directories and symlinks to enable partial rebuilding.
 	ContentChanges *contentChangeMap
 
diff --git a/hugolib/hugo_sites_build.go b/hugolib/hugo_sites_build.go
index ea73c493fc5..9a645f3a56f 100644
--- a/hugolib/hugo_sites_build.go
+++ b/hugolib/hugo_sites_build.go
@@ -25,6 +25,7 @@ import (
 	"github.com/bep/logg"
 	"github.com/gohugoio/hugo/langs"
 	"github.com/gohugoio/hugo/publisher"
+	"github.com/gohugoio/hugo/tpl"
 
 	"github.com/gohugoio/hugo/hugofs"
 
@@ -144,18 +145,8 @@ func (h *HugoSites) Build(config BuildCfg, events ...fsnotify.Event) error {
 			h.SendError(fmt.Errorf("render: %w", err))
 		}
 
-		if h.Configs.Base.LogPathWarnings {
-			// We need to do this before any post processing, as that may write to the same files twice
-			// and create false positives.
-			hugofs.WalkFilesystems(h.Fs.PublishDir, func(fs afero.Fs) bool {
-				if dfs, ok := fs.(hugofs.DuplicatesReporter); ok {
-					dupes := dfs.ReportDuplicates()
-					if dupes != "" {
-						h.Log.Warnln("Duplicate target paths:", dupes)
-					}
-				}
-				return false
-			})
+		if err := h.postRenderOnce(); err != nil {
+			h.SendError(fmt.Errorf("postRenderOnce: %w", err))
 		}
 
 		if err := h.postProcess(infol); err != nil {
@@ -329,6 +320,34 @@ func (h *HugoSites) render(l logg.LevelLogger, config *BuildCfg) error {
 	return nil
 }
 
+func (h *HugoSites) postRenderOnce() error {
+	h.postRenderInit.Do(func() {
+		conf := h.Configs.Base
+		if conf.PrintPathWarnings {
+			// We need to do this before any post processing, as that may write to the same files twice
+			// and create false positives.
+			hugofs.WalkFilesystems(h.Fs.PublishDir, func(fs afero.Fs) bool {
+				if dfs, ok := fs.(hugofs.DuplicatesReporter); ok {
+					dupes := dfs.ReportDuplicates()
+					if dupes != "" {
+						h.Log.Warnln("Duplicate target paths:", dupes)
+					}
+				}
+				return false
+			})
+		}
+
+		if conf.PrintUnusedTemplates {
+			unusedTemplates := h.Tmpl().(tpl.UnusedTemplatesProvider).UnusedTemplates()
+			for _, unusedTemplate := range unusedTemplates {
+				h.Log.Warnf("Template %s is unused, source file %s", unusedTemplate.Name(), unusedTemplate.Filename())
+			}
+		}
+
+	})
+	return nil
+}
+
 func (h *HugoSites) postProcess(l logg.LevelLogger) error {
 	defer h.timeTrack(l, time.Now(), "postProcess")
 
diff --git a/langs/i18n/i18n.go b/langs/i18n/i18n.go
index 1ebd039cd88..74af0775405 100644
--- a/langs/i18n/i18n.go
+++ b/langs/i18n/i18n.go
@@ -119,7 +119,7 @@ func (t Translator) initFuncs(bndl *i18n.Bundle) {
 				t.logger.Warnf("Failed to get translated string for language %q and ID %q: %s", currentLangStr, translationID, err)
 			}
 
-			if t.cfg.LogI18nWarnings() {
+			if t.cfg.PrintI18nWarnings() {
 				t.logger.Warnf("i18n|MISSING_TRANSLATION|%s|%s", currentLangStr, translationID)
 			}
 


Test patch:
diff --git a/config/allconfig/integration_test.go b/config/allconfig/integration_test.go
index 2de83eaa4cc..fcb92e71df3 100644
--- a/config/allconfig/integration_test.go
+++ b/config/allconfig/integration_test.go
@@ -69,3 +69,21 @@ Title: {{ .Title }}
 	b.Assert(modConf.Mounts[1].Lang, qt.Equals, "sv")
 
 }
+
+func TestConfigAliases(t *testing.T) {
+
+	files := `
+-- hugo.toml --
+baseURL = "https://example.com"
+logI18nWarnings = true
+logPathWarnings = true
+`
+	b := hugolib.NewIntegrationTestBuilder(
+		hugolib.IntegrationTestConfig{T: t, TxtarString: files},
+	).Build()
+
+	conf := b.H.Configs.Base
+
+	b.Assert(conf.PrintI18nWarnings, qt.Equals, true)
+	b.Assert(conf.PrintPathWarnings, qt.Equals, true)
+}