Permalinks config ignoring top-level section (but shouldn't be)

I’ve been successfully using Hugo on dozens of websites for several years, and just hit a weird bug that I can’t seem to fix or find a working solution for elsewhere.

In my config.yml file, my permalinks look like this…

  books: /:sections/:title/
  courses: /:sections/:title/

Both books and courses have a file structure that looks like this…

  |-- book-title/
      | --

  |-- course-title/
      | --

On my local machine, things render as expected.

But I also have an automated deploy from GitHub. When I push new code, my server pulls the latest commit, runs hugo, and copies the build files to production.

For whatever reason, on the server only, Hugo ignores the top-level directory under the courses Type. Instead of building to /courses/course-title/page-1/index.html, it builds to /courses/page-1/index.html.

I just added the courses type this week, but have been building the books Type like this successfully for years.

Both types use similar templates. Both my local machine and the server are running the same exact version of Hugo. Any idea what could be causing this, or where to start looking to debug it?

What version is this?

It’s quite old at this point: v0.54.0-B1A82C61

(I’ve put off updating because some of my code was later deprecated and it would be a lot of work to update across 20+ sites.)

That’s fine, one of the benefits of having one static binary.

To your problem, I don’t see any good reason why it should behave this way. I suspect the devil lives in some detail here, which is hard without seeing the full picture. I was a little curious and quickly tested a similar setup on my MacBook, and it works as expected running hugo server with version 0.54.

Exactly why I’m posting here! As noted, it also works fine on my MacBook.

Any additional information I could provide to help get to the root of this? Any footguns I should be looking at? That sort of thing?

If you’re using the same version in both places, then one of the differences between local and remote builds is…

automated deploy from GitHub. When I push new code, my server pulls the latest commit, runs hugo , and copies the build files to production.

I think I’d look there first, making sure you’re clearing stuff from last pull, last build, etc.

Is there any sort of Hugo cache I need to clear as well (besides the /public directory)?

You shouldn’t need to clear the Hugo cache; that’s for resources, remote data, and modules.

1 Like

Thanks! I even tried doing a full manual wipe and rebuild… same issue. This is going to vex me until my dying days!

Check your files. My theory is that you are running hugo server -D locally, and that draft is true is one of the files.

If you use a recent version of Hugo, if the file is draft, we don’t render any of the descendants. Not sure when that was changed, but quite some time ago.

I’m actually not running hugo server at all for this one, just hugo for a raw build. I’ve got some custom PHP files being generated by Hugo, so I’m loading up a PHP server instead.

I did check for draft files first as I saw that mentioned in another answer somewhere. Thanks for giving this more thought, though!

Well, that’s the only way I can reproduce your problem with v0.54.0.

This is the worst kind of bug: I can’t reproduce it myself anywhere but on the server.

Worse case scenario is I start manually FTPing things, I guess! LOL

Another wrinkle/data point:

I removed my custom permalink configuration, and now the files render with the proper directory structure, BUT… at one point in my template I range over the courses, and on my server only, that .Type isn’t recognized.

On my local machine, it loops fine. On the server, I get back an empty Map.

Any thoughts on what could be causing that discrepancy? Any configuration or setting I should be looking at?

I’d be happy to look at your project. Can you share your repository? Perhaps privately?

Absolutely. What’s the best way to make that happen? I’d be grateful for any help on this one. I must be missing something obvious.

If your repo is public, just DM the link. If private, invite me. My email address is on my GitHub profile.

It is private, but I just sent you a collaborator invite. Thanks so much, Joe!

1 Like

Oh, and if it’s at all useful to you, in themes/gmt/layouts/_default/home.php, this is returning empty the empty Map…

{{ $courses := where .Site.Pages "Type" "courses" }}

Using 0.54.0…

Locally… where .Site.Pages "Type" "courses" gives me 128 pages. So, as you say, this is on the server side.

I looked at the blame history on, and for a while you were pushing to main instead of master. Any chance the mechanism on your server is looking for main? Or a wrong branch there?