Hugo producing non-deterministic output

I’m at a loss as to what to do, so I’m submitting this here for your input. I’ve cannibalized my own theme out of primarily the Docdock theme, and I’ve somehow created a sidebar that doesn’t produce the same output every time the site is compiled.

Here’s the source (1.5MB). If you clone that, ./make.sh in the root of the repo will wipe ./public, run hugo, and diff public/3/3-1/index.html against public-bak/3/3-1/index.html (a previous output from the same setup). Obviously, review the contents of make.sh before running it. But if you run it 10-15 times, you should see multiple different outputs from the diff. Here’s some example output on Pastebin (16KB).

It seems like the problem is somewhere in themes/blank/layouts/partials/sidebar.html, but I really don’t understand where.

Yeah, that’s an understatement. I stripped out the cruft in that partial to fit the core logic on one screen, and it’s still non-deterministic. The contents of .Pages and .Section in the recursive template calls is just different from run to run [MacOS X 10.13.2, Hugo v0.34].

{{- range .Site.Home.Sections.ByTitle}}
  {{- template "section-tree-nav" . }}
{{- end}}

{{- define "section-tree-nav" }}
  {{- if .IsSection }}
    {{.Title}}
    {{- if ne (add (len .Pages) (len .Sections)) 0 }}
      {{- .Scratch.Set "pages" .Pages }}
      {{- if .Sections}}
        {{- .Scratch.Add "pages" .Sections }}
      {{- end}}
      {{- range (.Scratch.Get "pages").ByTitle }}
        {{- template "section-tree-nav" . }}
      {{- end}}
    {{- end}}
  {{- else}}
    {{.LinkTitle}}
  {{- end}}
{{- end}}

Testing with the following command line, the output was different every time:

rm -rf public*; hugo -d public1; hugo -d public2; diff -r public1 public2

-j

I would guess that you have duplicate/empty titles somewhere. The sort is stable (it keeps the original order of equal elements), but that will only help you within the same build,

No, his sample repo has distinct titles for all 12 files in content (11 different _index.md, plus testing.md). What’s changing is not the order, but the presence of some of the nested sections. In some cases, a section appears more than once in the output.

-j

If I strip out the use of .Scratch and print sub-sections and pages separately, the problem goes away. Maybe recursion and Scratch don’t mix? That would explain how sometimes you get multiple copies of the same sub-section name in the output.

{{- range .Site.Home.Sections.ByTitle }}
  {{- template "section-tree-nav" .}}
{{- end}}

{{- define "section-tree-nav" }}
  {{- if .IsSection }}
    {{.Title}}
    {{- range .Sections.ByTitle }}
      {{- template "section-tree-nav" . }}
    {{- end }}
    {{- range .Pages.ByTitle }}
      {{- template "section-tree-nav" . }}
    {{- end}}
  {{- else}}
    {{.LinkTitle}}
  {{- end}}
{{- end}}

Maybe:

That seems to have done it. I’ve cleaned up and fixed it in this commit. I’m not familiar enough with Go to know why that was an issue, but thanks!

Just hit the same bug. There is definitely something weird with .Scratch and recursion. This seemed to have fixed it. I now get stable output.

-          {{- .Scratch.Set "pages" .Pages }}
-          {{- if .Sections}}
-          {{- .Scratch.Set "pages" (.Pages | union .Sections) }}
-          {{- end}}
-          {{- $pages := (.Scratch.Get "pages") }}
+          {{- $pages := (.Pages | union .Sections) }}