Main Menu url being re-written incorrectly

Hi all,
I think this might be a bug, but I’m not sure if it’s just that I’m doing something wrong…


  • Internal Gitlab server, with Pages publishing setup
  • Projects use Hugo+Docsy to build their html documentation output, which the Pages deploy then puts on the internal hosting server
  • There are groups and sub-groups in use. Gitlab has an algorithm for its URL building that essentially goes: GROUP.internal.domain/PROJECT/ or GROUP.internal.domain/SUB-GROUP/PROJECT/ or GROUP.internal.domain/SUB-GROUP/SUB-SUB-GROUP/PROJECT/, etc
  • Our builds all have i18n turned on, and a default language of en (whilst we currently only have English outputs, this choice was to support future plans).

Thus, we have a group top-level project that produces output for GROUP.internal.domain/, and a menu link defined in config for a project in a subgroup, i.e. at GROUP.internal.domain/SUB-GROUP/PROJECT/.

When you visit GROUP.internal.domain/ it redirects to GROUP.internal.domain/en/ and similarly GROUP.internal.domain/SUB-GROUP/PROJECT/ redirects to GROUP.internal.domain/SUB-GROUP/PROJECT/en/ - this is all good and as expected.

However, the menu link in hugo.yaml for the top level project is defined as:

# hugo.yaml -- Base config
baseURL: https://epr.internal.domain/

# snip...

    - identifier: all-projects
      name: All Projects
      weight: 1000
      url: https://www.internal.domain/
    - identifier: mpages-build
      name: MPages
      weight: 800
      url: https://epr.internal.domain/mpages/build/

Where epr and www are top level groups, mpages is a subgroup of epr, and build is the name of the project in the mpages subgroup.

Unfortunately, whilst we’ve put an explicit FQDN for the mpages-build entry, that is being rewritten in the output to a relative url of:

      <li class="nav-item">
        <a class="nav-link" href="/en/mpages/build/" target="_blank" rel="noopener"><span>MPages</span></a>
      <li class="nav-item">
        <a class="nav-link" href="https://www.internal.domain/" target="_blank" rel="noopener"><span>All Projects</span></a>

Clicking the MPages link then takes you (as expected) to https://epr.internal.domain/en/mpages/build/, which doesn’t exist so 404’s (it obviously should be ending up at https://epr.internal.domain/mpages/build/en/)

I can see that it’s doing a basic find/replace of the base url here, but in this instance, I don’t want that to happen - so I’m not sure if this is a bug, or if there’s a way to configure this link so that it doesn’t get replaced?

Kind regards,

Also I cannot follow all the details your last statement:

So maybe you have that set in your config.

That might cause your problem

I haven’t read your whole post but if mpages is a page in your project, use pageRef instead of url in your menu definition: Menus | Hugo

Thanks for that pointer - though reading the docs it makes me think this is a bug:

From Menus | Hugo

  • pageRef
    (string) The logical path of the target page, relative to the content directory. Omit language code and file extension. Required for internal links.

  • url
    (string) Required for external links.

I’m using url, as this should be treated as an external link.

What I’m not clear on is if this rewrite issue arises in Hugo or in a theme template

Thanks - there’s no canonifyURLs in the site config, so I’m assuming it’s a default value.

Though I note the docs say this is to be considered deprecated:

This is an imperfect, brute force approach that can affect content as well as HTML attributes. As noted above, this is a legacy configuration option that will likely be removed in a future release.

I don’t think relativeURLs is applicable to this solution either

The first seems like it could be a way to brute force solve the problem - the fact it may be removed though doesn’t fill me with confidence to use it :-/

If you don’t have that in, I would also not go with it.
Ootb hugo does not do anything like that without explicitely asked for.

That maye would be the right time to share your repo.


If I’m reading the above correctly, you’re stating that Hugo is rewriting this:


To this:


If my understanding is correct, that’s not something Hugo does internally, and we don’t have a menu method or setting that would cause that to happen.

I’d look carefully at the code that renders the menu.

1 Like

Maybe I’m wrong… quite a fresher and not yet done many things with languages and menus/navigation but taking the chance to learn…

I think the Problem is in docsy/layouts/partials/navbar.html at main · google/docsy · GitHub

  1. secondary problem in line 5 : {{ $baseURL := urls.Parse $.Site.Params.Baseurl -}}

    this is empty and later used for testing if it is an external site → the only reason why your url for MPages is treated as external because “” differs from any valid baseurl (line 38)

  2. main problem in lines 32-36

  • your MPages is not a page of your site

  • so the else is triggered

  • with will return the relLangURL

    • which will strip off the domain Part cause it’s the same as sites BaseUrl
         {{ with .Page -}}
           {{ $active = or $active ( $.IsDescendant .) -}}
           {{ $href = .RelPermalink -}}
         {{ else -}}
           {{ $href = .URL | relLangURL -}}
         {{ end -}}

tested with an ootb docsy with your config snippets (which fe. lacks the language and maybe other settings) so there might be a choice for me to fail.


Thank you both @jmooring & @irkode

That the issue resides in a FQDN URI being set in the Menus configuration block and that the Multilingual features being enabled made me think this was more a Hugo than a Docsy problem to start with.

I think irkode’s astute digging into the Docsy side makes this look more like an unintended consequence of how Docsy is handling this data - so I’ll go and drop a report over there.

In the meantime I’m not sure what the solution is, but hopefully keener minds will have a clue.


1 Like

If you need a workaround until you get an answer you could copy the affected template from the docsy theme to your own layouts folder and customize to your needs which is the official way to customize a theme.

Be careful maybe changing some stuff there will break other places.

I was just looking through it and thinking very similar things.

In essence, if I put a markdown link into my content with a FQDN URI, (i.e. [link](, then this tends to be left alone in output. If I use a shortcode to reference an internal page (i.e. [link]({{< ref "/subfolder/" >}}) then that gets correctly rewritten in relation to the baseURL specified.

The challenge here is that this is a link defined in config for a common header element, and it can’t distinguish between a FQDN that starts with the baseURL but isn’t a page in this site.

If I’m understanding the test they’re using for “external” later on ({{ $isExternal := ne $baseURL.Host (urls.Parse .URL).Host -}} - this is just looking at the baseURL and hostname, and completely negates checking if this is a page within this site, or another page that happens to share the same hostname.

I’m far from feeling competent with Go and this templating language, so I’m wary about proposing any solution, but I’m having a little bit of a challenge working out if there’s a quick/easy way to test whether a complete URL maps to an page in the site or not

… edit:

And a solution that respects that the site could have a valid page at the same URL as the sub-group’s url location!

i.e. a page in both projects could resolve to something like https://epr.internal.domain/mpages/build/foo/. The only difference would be visible in the placement of the multilingual support, thus it would be https://epr.internal.domain/mpages/build/en/foo/ vs https://epr.internal.domain/en/mpages/build/foo

For a patch i would concentrate only of the problem you currently have. And i I understood the setup right the problematic line for you is:

{{ $href = .URL | relLangURL

The langague part of that line works. Right?
So i would just re add the base url in case the current url is in a list where you want to keep it.

Pseudocode :
Prepend current basurl if currenBaseur in listtokeep

Listtokeep could be defines as an array in frontmatter.


  • urls.parse to get the current baseurl
  • Collections.In to check
  • add or printf to combine that
  • site.params for the array

Don’t rely on exact typing. Just mobile conected at the moment

Just try and post how far you got in case of problems

1 Like

Issue logged with Docsy at Main Menu url being re-written incorrectly · Issue #2043 · google/docsy · GitHub

In the meantime I’ll have a play around with some workarounds suggested

Thank you all!