gohugoio / hugo

The world’s fastest framework for building websites.
https://gohugo.io
Apache License 2.0
75.9k stars 7.54k forks source link

panic: tableofcontents.Heading.IsZero called using nil *Heading pointer #11843

Open skrysmanski opened 10 months ago

skrysmanski commented 10 months ago

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

$ hugo version
hugo v0.121.1-00b46fed8e47f7bb0a85d7cfc2d9f1356379b740+extended windows/amd64 BuildDate=2023-12-08T08:47:45Z VendorInfo=gohugoio

Does this issue reproduce with the latest release?

Yes

Bug Report

When running Hugo as server, I'm getting this error (I'm not getting this error when just executing hugo):

$ hugo server --bind 0.0.0.0 -D
Watching for changes in D:\Programmieren\_Docs\docs-hub\{content,static,themes}
Watching for config changes in D:\Programmieren\_Docs\docs-hub\hugo.yaml
Start building sites …
hugo v0.121.1-00b46fed8e47f7bb0a85d7cfc2d9f1356379b740+extended windows/amd64 BuildDate=2023-12-08T08:47:45Z VendorInfo=gohugoio

panic: value method github.com/gohugoio/hugo/markup/tableofcontents.Heading.IsZero called using nil *Heading pointer [recovered]
        panic: value method github.com/gohugoio/hugo/markup/tableofcontents.Heading.IsZero called using nil *Heading pointer

goroutine 399 [running]:
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.errRecover(0xc00222d470)
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:171 +0x16c
panic({0x2a54da0?, 0xc001e03780?})
        /usr/local/go/src/runtime/panic.go:914 +0x21f
github.com/gohugoio/hugo/markup/tableofcontents.(*Heading).IsZero(0x2a80420?)
        <autogenerated>:1 +0x5c
github.com/gohugoio/hugo/common/hreflect.IsTruthfulValue({0x2a80420?, 0x0?, 0xc001e03560?})
        /root/project/hugo/common/hreflect/helpers.go:94 +0x334
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.isTrue(...)
        /root/project/hugo/tpl/internal/go_templates/texttemplate/hugo_template.go:380
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walkIfOrWith(0xc00222d520, 0xa, {0x2d39320?, 0xc001e03560?, 0xc0007ed4a0?}, 0x0?, 0x0?, 0x0)
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:303 +0xd0
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walk(0xc00222d520, {0x2d39320?, 0xc001e03560?, 0xc00220eb20?}, {0x4414b18?, 0xc000256a80?})
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:278 +0x14d
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walk(0xc00222d520, {0x2d39320?, 0xc001e03560?, 0x2d39320?}, {0x4414890?, 0xc0007f1710?})
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:281 +0x2aa
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walkIfOrWith(0xc00222d520, 0xa, {0x2d39320?, 0xc001e03560?, 0xc001e03560?}, 0x99?, 0x0?, 0xc0007f1a40)
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:311 +0x138
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walk(0xc00222d520, {0x2d39320?, 0xc001e03560?, 0xc0026b7132?}, {0x4414b18?, 0xc000256ac0?})
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:278 +0x14d
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walk(0xc00222d520, {0x2d39320?, 0xc001e03560?, 0xc001e03700?}, {0x4414890?, 0xc0007f1650?})
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:281 +0x2aa
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walkIfOrWith(0xc00222d520, 0xa, {0x2d39320?, 0xc001e03560?, 0xc0007ed320?}, 0x154c00007f0cf0?, 0x92?, 0x0)
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:311 +0x138
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walk(0xc00222d520, {0x2d39320?, 0xc001e03560?, 0x2a7ab00?}, {0x4414b18?, 0xc000256b00?})
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:278 +0x14d
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walk(0xc00222d520, {0x2d39320?, 0xc001e03560?, 0xc001e034e0?}, {0x4414890?, 0xc0007f0ea0?})
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:281 +0x2aa
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walkIfOrWith(0xc00222d520, 0x13, {0x2ce5ee0?, 0xc0017f6480?, 0xc0007ed020?}, 0x2?, 0x0?, 0xc0007f1b30)
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:309 +0x10e
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walk(0xc00222d520, {0x2ce5ee0?, 0xc0017f6480?, 0xc00220eae8?}, {0x4414b60?, 0xc000256c00?})
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:292 +0x215
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walk(0xc00222d520, {0x2ce5ee0?, 0xc0017f6480?, 0xc00220eab0?}, {0x4414890?, 0xc0007f0d20?})
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:281 +0x2aa
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walkIfOrWith(0xc00222d520, 0xa, {0x2ce5ee0?, 0xc0017f6480?, 0xc0007ecf60?}, 0x0?, 0xc00222ce68?, 0xc0007f1cb0)
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:311 +0x138
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walk(0xc00222d520, {0x2ce5ee0?, 0xc0017f6480?, 0xc001e03480?}, {0x4414b18?, 0xc000256fc0?})
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:278 +0x14d
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walk(0xc00222d520, {0x2ce5ee0?, 0xc0017f6480?, 0x2ce5ee0?}, {0x4414890?, 0xc0007f0b70?})
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:281 +0x2aa
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walkIfOrWith(0xc00222d520, 0x13, {0x2ce5ee0?, 0xc0017f6480?, 0xc0017f6480?}, 0xc001c739f0?, 0x0?, 0xc0007f0b70)
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:314 +0x16a
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walk(0xc00222d520, {0x2ce5ee0?, 0xc0017f6480?, 0xc0026b7090?}, {0x4414b60?, 0xc000257000?})
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:292 +0x215
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walk(0xc00222d520, {0x2ce5ee0?, 0xc0017f6480?, 0x564fe00?}, {0x4414890?, 0xc0007f0720?})
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:281 +0x2aa
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walkIfOrWith(0xc00222d520, 0xa, {0x2ce5ee0?, 0xc0017f6480?, 0xc0007ec5a0?}, 0x296dec0?, 0x0?, 0xc0007f0720)
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:314 +0x16a
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walk(0xc00222d520, {0x2ce5ee0?, 0xc0017f6480?, 0xc001e033b0?}, {0x4414b18?, 0xc000257040?})
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:278 +0x14d
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walk(0xc00222d520, {0x2ce5ee0?, 0xc0017f6480?, 0x564fe00?}, {0x4414890?, 0xc0007bdaa0?})
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:281 +0x2aa
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walkIfOrWith(0xc00222d520, 0xa, {0x2ce5ee0?, 0xc0017f6480?, 0xc0007ec480?}, 0x1e07d1f?, 0xc00222d550?, 0xc0008003f0)
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:311 +0x138
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walk(0xc00222d520, {0x2ce5ee0?, 0xc0017f6480?, 0xc00222d448?}, {0x4414b18?, 0xc000257180?})
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:278 +0x14d
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*state).walk(0xc00222d520, {0x2ce5ee0?, 0xc0017f6480?, 0x30?}, {0x4414890?, 0xc0007bd770?})
        /root/project/hugo/tpl/internal/go_templates/texttemplate/exec.go:281 +0x2aa
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*Template).executeWithState(0x6820e5?, 0x1e12840?, {0x2ce5ee0?, 0xc0017f6480?, 0xc00222d5c8?})
        /root/project/hugo/tpl/internal/go_templates/texttemplate/hugo_template.go:119 +0x125
github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate.(*executer).ExecuteWithContext(0xc000454b50, {0x440fda0, 0xc0025b5710}, {0x243f8088440?, 0xc0006a2c30}, {0x43f76c0?, 0xc0027c3110}, {0x2ce5ee0, 0xc0017f6480})
        /root/project/hugo/tpl/internal/go_templates/texttemplate/hugo_template.go:106 +0x2d6
github.com/gohugoio/hugo/tpl/tplimpl.(*templateExec).ExecuteWithContext(0xc000a29b90, {0x440fda0, 0xc0025b5710}, {0x4400910?, 0xc0006a2c30}, {0x43f76c0, 0xc0027c3110}, {0x2ce5ee0, 0xc0017f6480})
        /root/project/hugo/tpl/tplimpl/template.go:264 +0x64c
github.com/gohugoio/hugo/hugolib.hookRendererTemplate.RenderLink(...)
        /root/project/hugo/hugolib/site.go:1087
github.com/gohugoio/hugo/markup/goldmark.(*hookedRenderer).renderLink(0xc00052ab10?, {0x4416f70?, 0xc0027c3110?}, {0xc002200000, 0x2be9, 0x30eb}, {0x4429428?, 0xc001f13ea0}, 0x0)
        /root/project/hugo/markup/goldmark/render_hooks.go:274 +0x5d6
github.com/yuin/goldmark/renderer.(*renderer).Render.func2({0x4429428, 0xc001f13ea0}, 0x10?)
        /root/project/gomodcache/github.com/yuin/goldmark@v1.6.0/renderer/renderer.go:166 +0xc5
github.com/yuin/goldmark/ast.walkHelper({0x4429428, 0xc001f13ea0}, 0xc00222dc58)
        /root/project/gomodcache/github.com/yuin/goldmark@v1.6.0/ast/ast.go:503 +0xb1
github.com/yuin/goldmark/ast.walkHelper({0x442a088, 0xc001e90080}, 0xc00222dc58)
        /root/project/gomodcache/github.com/yuin/goldmark@v1.6.0/ast/ast.go:498 +0x85
github.com/yuin/goldmark/ast.walkHelper({0x4428e88, 0xc0031fa5a0}, 0xc00222dc58)
        /root/project/gomodcache/github.com/yuin/goldmark@v1.6.0/ast/ast.go:498 +0x85
github.com/yuin/goldmark/ast.Walk(...)
        /root/project/gomodcache/github.com/yuin/goldmark@v1.6.0/ast/ast.go:487
github.com/yuin/goldmark/renderer.(*renderer).Render(0xc000592910, {0x43f76c0?, 0xc0027c3110?}, {0xc002200000, 0x2be9, 0x30eb}, {0x4428e88, 0xc0031fa5a0})
        /root/project/gomodcache/github.com/yuin/goldmark@v1.6.0/renderer/renderer.go:161 +0x205
github.com/gohugoio/hugo/markup/goldmark.(*goldmarkConverter).Render(0xc001f13040, {{0x440fda0, 0xc0025b5710}, {0xc002200000, 0x2be9, 0x30eb}, 0x1, 0xc0027c2c30}, {0x2d20e40, 0xc0031fa5a0})
        /root/project/hugo/markup/goldmark/convert.go:254 +0x35f
github.com/gohugoio/hugo/hugolib.(*pageContentOutput).RenderContent(0xc001094960, {0x440fda0, 0xc0025b5710}, {0xc002200000, 0x2be9, 0x30eb}, {0x2d20e40, 0xc0031fa5a0})
        /root/project/hugo/hugolib/page__per_output.go:859 +0x172
github.com/gohugoio/hugo/hugolib.newPageContentOutput.func2({0x440fda0, 0xc0025b5710})
        /root/project/hugo/hugolib/page__per_output.go:200 +0xe3
github.com/gohugoio/hugo/hugolib.newPageContentOutput.func4({0x440fda0?, 0xc0025b5710?})
        /root/project/hugo/hugolib/page__per_output.go:287 +0x22
github.com/gohugoio/hugo/lazy.(*Init).withTimeout.func1()
        /root/project/hugo/lazy/init.go:189 +0x42
created by github.com/gohugoio/hugo/lazy.(*Init).withTimeout in goroutine 397
        /root/project/hugo/lazy/init.go:188 +0x147

The panic is caused by the if $targetHeading condition from within the link render hook (render-link.html):

{{- $targetHeading := index .Fragments.HeadingsMap $url.Fragment -}}
{{- if $targetHeading -}}
  {{- $text = $targetHeading.Title -}}
{{- end -}}

The value for $url.Fragment here is "exporting_classes".

The value for .Fragments.HeadingsMap is:

map[string]*tableofcontents.Heading{
  "creating-the-library-project": &tableofcontents.Heading{
    ID: "creating-the-library-project",
    Level: 2,
    Title: "Creating the Library Project",
    Headings: nil,
  },
  "dllimport-necessary": &tableofcontents.Heading{
    ID: "dllimport-necessary",
    Level: 2,
    Title: "dllimport necessary?",
    Headings: nil,
  },
  "exporting-classes": &tableofcontents.Heading{
    ID: "exporting-classes",
    Level: 2,
    Title: "Exporting Classes",
    Headings: nil,
  },
  "library-projects": &tableofcontents.Heading{
    ID: "library-projects",
    Level: 2,
    Title: "Library Projects",
    Headings: nil,
  },
  "writing-a-reusable-class": &tableofcontents.Heading{
    ID: "writing-a-reusable-class",
    Level: 2,
    Title: "Writing a Reusable Class",
    Headings: nil,
  },
}
skrysmanski commented 10 months ago

After some more digging I found out that my code was (mistakenly) looking for exporting_classes (underscore) but should have been looking for exporting-classes (dash).

But still I'd argue that looking up a non-existing key shouldn't crash hugo server.

jmooring commented 10 months ago

No problem:

{{ $h := .Fragments.HeadingsMap.bad_id }}
{{ if $h }}
{{ end }}

Also no problem:

{{ $h := index .Fragments.HeadingsMap "bad_id" }}

This panics:

{{ $h := index .Fragments.HeadingsMap "bad_id" }}
{{ if $h }}
{{ end }}