Hugo: Hugo panics under certain conditions when the --layoutDir flag is set

Created on 29 Oct 2017  路  3Comments  路  Source: gohugoio/hugo

I originally posted this in issue #3568 but was advised it's slightly different than that one and should be it's own issue. The snips below are from MacOS Sierra (10.12.5) with hugo 0.25.1, but the error has been recreated on MacOS High Sierra with hugo 0.30.2 and also on Linux (OpenSuSE Leap 42.3) with hugo 0.30.2.

Three conditions must be met for the panic to occur:

  • the --layoutDir argument is given on the command line
  • the argument to the --layoutDir argument contains a non-terminating slash
  • the directory pointed to by the --layoutDir is not empty

So if you fire up a new hugo directory, download a theme, config and run hugo, you won't have a problem. But as soon as you put something (even an empty file) in the layouts directory, it fails:

MacBook-Pro:/tmp/hugotest> uname -a
Darwin MacBook-Pro-3 16.6.0 Darwin Kernel Version 16.6.0: Fri Apr 14 16:21:16 PDT 2017; root:xnu-3789.60.24~6/RELEASE_X86_64 x86_64

MacBook-Pro:/tmp/hugotest> hugo version
Hugo Static Site Generator v0.25.1 darwin/amd64 BuildDate: 2017-07-10T03:57:59-03:00

MacBook-Pro:/tmp/hugotest> ls
archetypes      config.toml     content         data            layouts         public          static          themes

MacBook-Pro:/tmp/hugotest> ls layouts/
MacBook-Pro:/tmp/hugotest>

MacBook-Pro:/tmp/hugotest> hugo --quiet --themesDir ./themes/
MacBook-Pro:/tmp/hugotest>

MacBook-Pro:/tmp/hugotest> hugo --themesDir ./themes/ --layoutDir ./layouts --quiet
MacBook-Pro:/tmp/hugotest>

MacBook-Pro:/tmp/hugotest> touch layouts/index.html
MacBook-Pro:/tmp/hugotest> hugo --themesDir ./themes/ --layoutDir ./layouts --quiet                          
panic: runtime error: slice bounds out of range

goroutine 1 [running]:
github.com/gohugoio/hugo/tpl/tplimpl.(*templateHandler).loadTemplates.func1(0xc42037e7b0, 0x2e, 0x1b5f600, 0xc4202e9c70, 0x0, 0x
0, 0xc420341370, 0x10879bb)
        /Users/bep/go/src/github.com/gohugoio/hugo/tpl/tplimpl/template.go:448 +0xd2e
github.com/gohugoio/hugo/vendor/github.com/spf13/afero.walk(0x1b61260, 0x1bcf900, 0xc42037e7b0, 0x2e, 0x1b5f600, 0xc4202e9c70, 0
xc42037e690, 0x0, 0x2e)
        /Users/bep/go/src/github.com/gohugoio/hugo/vendor/github.com/spf13/afero/path.go:44 +0x81
github.com/gohugoio/hugo/vendor/github.com/spf13/afero.Walk(0x1b61260, 0x1bcf900, 0xc42037e7b0, 0x2e, 0xc42037e690, 0x1, 0x1)
        /Users/bep/go/src/github.com/gohugoio/hugo/vendor/github.com/spf13/afero/path.go:107 +0x103
github.com/gohugoio/hugo/helpers.SymbolicWalk(0x1b61260, 0x1bcf900, 0xc42037e660, 0x23, 0xc42037e690, 0x2, 0x23)
        /Users/bep/go/src/github.com/gohugoio/hugo/helpers/path.go:513 +0x2ef
github.com/gohugoio/hugo/tpl/tplimpl.(*templateHandler).loadTemplates(0xc4202ea980, 0xc42037e660, 0x23, 0x0, 0x0)
        /Users/bep/go/src/github.com/gohugoio/hugo/tpl/tplimpl/template.go:480 +0x200
github.com/gohugoio/hugo/tpl/tplimpl.(*templateHandler).LoadTemplates(0xc4202ea980, 0xc42037e660, 0x23, 0x0, 0x0)
        /Users/bep/go/src/github.com/gohugoio/hugo/tpl/tplimpl/template.go:290 +0x53
github.com/gohugoio/hugo/hugolib.(*Site).withSiteTemplates.func1(0x1b5fba0, 0xc4202ea980, 0x0, 0x1bcfc18)
        /Users/bep/go/src/github.com/gohugoio/hugo/hugolib/hugo_sites.go:159 +0x80
github.com/gohugoio/hugo/tpl/tplimpl.(*TemplateProvider).Update(0x0, 0xc42027ad80, 0x0, 0x0)
        /Users/bep/go/src/github.com/gohugoio/hugo/tpl/tplimpl/templateProvider.go:35 +0x4c4
github.com/gohugoio/hugo/deps.(*Deps).LoadResources(0xc42027ad80, 0xc420182300, 0xc4202e6d80)
        /Users/bep/go/src/github.com/gohugoio/hugo/deps/deps.go:68 +0x72
github.com/gohugoio/hugo/hugolib.applyDepsIfNeeded(0xc420070100, 0xc420182300, 0xc4202e6d80, 0x1b5fd80, 0xc420165770, 0x1b587e0,
 0x0, 0xc4202cf200, 0x1b58760, 0xc4202ec260, ...)
        /Users/bep/go/src/github.com/gohugoio/hugo/hugolib/hugo_sites.go:130 +0x301
github.com/gohugoio/hugo/hugolib.newHugoSites(0xc420070100, 0xc420182300, 0x0, 0x1b5fd80, 0xc420165770, 0x0, 0x0, 0x0, 0x0, 0x0,
 ...)
        /Users/bep/go/src/github.com/gohugoio/hugo/hugolib/hugo_sites.go:89 +0x2e6
github.com/gohugoio/hugo/hugolib.NewHugoSites(0xc420070100, 0xc420182300, 0x0, 0x1b5fd80, 0xc420165770, 0x0, 0x0, 0x0, 0x0, 0x0,
 ...)
        /Users/bep/go/src/github.com/gohugoio/hugo/hugolib/hugo_sites.go:154 +0xce
github.com/gohugoio/hugo/commands.(*commandeer).initSites(0xc420254480, 0x17, 0xc420248300)
        /Users/bep/go/src/github.com/gohugoio/hugo/commands/hugo.go:733 +0x56
github.com/gohugoio/hugo/commands.(*commandeer).buildSites(0xc420254480, 0x0, 0x0, 0x10)
        /Users/bep/go/src/github.com/gohugoio/hugo/commands/hugo.go:744 +0x32
github.com/gohugoio/hugo/commands.(*commandeer).build(0xc420254480, 0x0, 0x0, 0x0, 0x0, 0x0)
        /Users/bep/go/src/github.com/gohugoio/hugo/commands/hugo.go:521 +0xa7
github.com/gohugoio/hugo/commands.glob..func8(0x1ba9aa0, 0xc420018af0, 0x0, 0x5, 0x0, 0x0)
        /Users/bep/go/src/github.com/gohugoio/hugo/commands/hugo.go:133 +0xb2
github.com/gohugoio/hugo/vendor/github.com/spf13/cobra.(*Command).execute(0x1ba9aa0, 0xc4200100d0, 0x5, 0x5, 0x1ba9aa0, 0xc42001
00d0)
        /Users/bep/go/src/github.com/gohugoio/hugo/vendor/github.com/spf13/cobra/command.go:647 +0x3f8
github.com/gohugoio/hugo/vendor/github.com/spf13/cobra.(*Command).ExecuteC(0x1ba9aa0, 0x1811fa8, 0x100610c, 0xc4200100b8)
        /Users/bep/go/src/github.com/gohugoio/hugo/vendor/github.com/spf13/cobra/command.go:726 +0x339
github.com/gohugoio/hugo/commands.Execute()
        /Users/bep/go/src/github.com/gohugoio/hugo/commands/hugo.go:172 +0x60
main.main()
        /Users/bep/go/src/github.com/gohugoio/hugo/main.go:27 +0x36

Interestingly, if you use a trailing slash on the layouts directory, you see a fencepost error in the path:

MacBook-Pro:/tmp/hugotest> hugo --themesDir ./themes/ --layoutDir layouts/ --quiet
ERROR 2017/07/13 00:10:28 Failed to resolve template in path "/tmp/hugotest/layouts/index.html": open /tmp/hugotest/layouts/ndex.html: no such file or directory

Also interesting, if you don't specify a layouts directory, everything works fine:

MacBook-Pro:/tmp/hugotest> hugo --themesDir ./themes/ --quiet
MacBook-Pro:/tmp/hugotest>

That a --layoutDir argument triggers it makes sense given that the stack trace points at line 448 of hugo/tpl/tplimpl/template.go which is pretty explicitly operating on the path of the layout directory:

template.go lines 446 - 448:

li := strings.LastIndex(path, layoutDir) + len(layoutDir) + 1
relPath := path[li:]
templateDir := path[:li-len(layoutDir)-1]
Bug

Most helpful comment

With a bit more testing, it seems like the bug occurs if layoutDir is specified with multiple folders in its path:

  • layoutDir = "src/layouts" is bugged.
  • layoutDir = "x/layouts" is bugged.
  • layoutDir = "layouts" is fine.
  • layoutDir = "testlayouts" is fine.

Unfortunately I need the src directory for my project structure. Moving the config.toml file down into the src directory, and changing my publishDir setting to point up to the above directory could be a possible workaround, but I don't want to move my config.toml file down either. I want it to be in the root of the project.

Could this bug get some attention please? It seems to have been reported several months ago. All I want to do is change the layout directory using the given layoutDir config option, but it doesn't work as expected.

All 3 comments

I believe I'm experiencing this issue. I'm new to Hugo and have put together a basic project structure for it. Tried to build it and then:

Building sites ... panic: runtime error: slice bounds out of range
github.com/gohugoio/hugo/tpl/tplimpl.(*templateHandler).loadTemplates.func1

However, unlike in the OP, I am just specifying layoutDir in my config.toml file. It's holding one shortcode template file. My Hugo config:

baseURL = "https://test.janesmith.com/"
title = "Test Title"
languageCode = "en-us"
relativeURLs = true
disableHugoGeneratorInject = true
publishDir = "build/public"
archetypeDir = "src/archetypes"
contentDir = "src/content"
dataDir = "src/data"
layoutDir = "src/layouts"
staticDir = "src/static"
themesDir = "src/themes"

My shortcode template is called "php.html":

<div>
    {{ safeHTML .Inner  }}
</div>

I got this shortcode template from this article, which happened to be literally the only thing I could find about using PHP with Hugo.

Could someone help me please? I don't think I'm doing anything crazy or really fancy. It's almost entirely a new, empty Hugo project, just with a test.md file in /src/content/, a config file specifying some custom directories, and the php.html template file. Why can't I build it?

With a bit more testing, it seems like the bug occurs if layoutDir is specified with multiple folders in its path:

  • layoutDir = "src/layouts" is bugged.
  • layoutDir = "x/layouts" is bugged.
  • layoutDir = "layouts" is fine.
  • layoutDir = "testlayouts" is fine.

Unfortunately I need the src directory for my project structure. Moving the config.toml file down into the src directory, and changing my publishDir setting to point up to the above directory could be a possible workaround, but I don't want to move my config.toml file down either. I want it to be in the root of the project.

Could this bug get some attention please? It seems to have been reported several months ago. All I want to do is change the layout directory using the given layoutDir config option, but it doesn't work as expected.

I'm unable to reproduce this issue today. Looks like it was fixed in Hugo 0.42. Closing.

Was this page helpful?
0 / 5 - 0 ratings