Repository: mkdocs/mkdocs

Issue:
404 page: navigation links are broken
# Issue

When hitting a missing page (404), the navigation links are not working anymore. 
The page link contains the base URL.

# Steps to reproduce

1. Visit https://arnaudbreton.github.io/mkdocs-404-nav-issue/hello => works. HW nav link is well formed.
2. Go to https://arnaudbreton.github.io/mkdocs-404-nav-issue/hello/missing.
3. Hover the "HW" nav link. It's "/hello/hello/" when it should "/hello".
4. Clicking on it keep appending the previous path.

Source repository is here: https://github.com/arnaudbreton/mkdocs-404-nav-issue
It's as minimal as possible to nail down the issue.

I hope I don't do things the right way.
Thanks for your help!


Discussion:
I notice you do not have the `site_url` config setting set. I suspect the issue would be resolved by setting that setting. See [this comment][1] for a detailed explanation of why that would matter.

That said, we should be able to make a guess if/when the `site_url` is not set. I think a reasonable approach would be that if it is not set, assume the mkdocs root is at the server root. In other words, for error pages,  `base_url` should be `/` if `site_url` is `None`.

This problem cannot be reproduced with the dev sever as the dev server overrides the `site_url` setting to have it point at the dev server. Therefore, when using the dev server, the `site_url` setting is always set. However, we can't make the site_url "required" as users who build their docs for browsing on the file system (`file://`) do not need or want the `site_url` setting.

And that is why having a default seems to be the best approach. For those who host their sites in subdirs, they simply need to set the optional setting (`site_url`). For everyone else, it "just works".

[1]: https://github.com/mkdocs/mkdocs/issues/77#issuecomment-242777289
@waylan thx for the quick feedback!

> This problem cannot be reproduced with the dev sever as the dev server overrides the site_url setting to have it point at the dev server

You mean `mkdocs serve`, right? If yes, I can reproduce there too.
Also, on our production doc - the one I'm troubleshooting - we've set the `site_url` to our doc root:

```yaml
...
site_url: https://docs.sqreen.io/
...
```

As you can see visiting https://docs.sqreen.io/iam/missing, it breaks the nav too.
Well I just found a bug. If base_url is `/` it is getting stripped to an empty string. Turns out we had a couple bad tests. <del>And as this doesn't apply in the dev server, we missed it.</del> Unfortunately, for 1.0.0 and 1.0.1, setting the `site_url` to the server root is not a workaround. We'll try to get a fix released ASAP.

Resolving patch:
diff --git a/mkdocs/commands/build.py b/mkdocs/commands/build.py
--- a/mkdocs/commands/build.py
+++ b/mkdocs/commands/build.py
@@ -52,7 +52,7 @@ def get_context(nav, files, config, page=None, base_url=''):
         'nav': nav,
         'pages': files.documentation_pages(),
 
-        'base_url': base_url.rstrip('/'),
+        'base_url': base_url,
 
         'extra_css': extra_css,
         'extra_javascript': extra_javascript,
@@ -78,8 +78,10 @@ def _build_template(name, template, files, config, nav):
     if utils.is_error_template(name):
         # Force absolute URLs in the nav of error pages and account for the
         # possability that the docs root might be different than the server root.
-        # See https://github.com/mkdocs/mkdocs/issues/77
-        base_url = utils.urlparse(config['site_url']).path
+        # See https://github.com/mkdocs/mkdocs/issues/77.
+        # However, if site_url is not set, assume the docs root and server root
+        # are the same. See https://github.com/mkdocs/mkdocs/issues/1598.
+        base_url = utils.urlparse(config['site_url'] or '/').path
     else:
         base_url = utils.get_relative_url('.', name)
 


Test patch:
diff --git a/mkdocs/tests/build_tests.py b/mkdocs/tests/build_tests.py
--- a/mkdocs/tests/build_tests.py
+++ b/mkdocs/tests/build_tests.py
@@ -91,22 +91,22 @@ def test_context_base_url_relative_no_page_use_directory_urls(self):
     def test_context_base_url_absolute_no_page(self):
         cfg = load_config(use_directory_urls=False)
         context = build.get_context(mock.Mock(), mock.Mock(), cfg, base_url='/')
-        self.assertEqual(context['base_url'], '')
+        self.assertEqual(context['base_url'], '/')
 
     def test_context_base_url__absolute_no_page_use_directory_urls(self):
         cfg = load_config()
         context = build.get_context(mock.Mock(), mock.Mock(), cfg, base_url='/')
-        self.assertEqual(context['base_url'], '')
+        self.assertEqual(context['base_url'], '/')
 
     def test_context_base_url_absolute_nested_no_page(self):
         cfg = load_config(use_directory_urls=False)
         context = build.get_context(mock.Mock(), mock.Mock(), cfg, base_url='/foo/')
-        self.assertEqual(context['base_url'], '/foo')
+        self.assertEqual(context['base_url'], '/foo/')
 
     def test_context_base_url__absolute_nested_no_page_use_directory_urls(self):
         cfg = load_config()
         context = build.get_context(mock.Mock(), mock.Mock(), cfg, base_url='/foo/')
-        self.assertEqual(context['base_url'], '/foo')
+        self.assertEqual(context['base_url'], '/foo/')
 
     def test_context_extra_css_js_from_homepage(self):
         nav_cfg = [