Skip to content

Docs site — running & troubleshooting ​

How to run the documentation site (this VitePress site) locally, and the pitfalls you'll hit when you try. Same format as the other troubleshooting pages: symptom, cause, fix, why.

The site lives in documentation/ at the repo root. It's a VitePress project — Vite + Vue + Markdown — that builds a static site from the .md files under guide/en/ and guide/fr/.


Quick reference ​

From the documentation/ directory:

bash
npm install            # once, to pull VitePress
npm run docs:dev       # local dev server with hot reload — http://localhost:5173
npm run docs:build     # static build to .vitepress/dist/
npm run docs:preview   # serve the production build locally

Rule of thumb: use docs:dev while writing — it's tolerant and fast. Run docs:build before pushing — it catches dead links and other errors that docs:dev ignores.


Symptom ​

(!) Found dead link ./../../VPS_SETUP in file guide\en\docker-vps-migration.md
(!) Found dead link ./../../VPS_SECURITY in file guide\en\docker-vps-migration.md
...
x Build failed in 1.48s
build error:
[vitepress] 8 dead link(s) found.

The dev server (docs:dev) works fine on the same files. Only docs:build fails.

Cause ​

VitePress resolves every markdown link at build time. If a relative link target doesn't exist on disk — even a link to a file outside the documentation/ tree — the build fails. The dev server doesn't enforce this check.

The trap: links like [VPS_SETUP.md](../../VPS_SETUP.md) are written assuming the file lives at the repo root (snag-tcg/VPS_SETUP.md). If those root-level files never got committed (or got moved), the build breaks even though the markdown reads fine.

Fix — 3 options, in order of preference ​

(a) Remove or repoint the link (clean, when the target really doesn't exist)

Replace the link with plain text, or repoint it to a page that does exist inside documentation/. This is the right answer when the linked file was never committed.

(b) Create the missing file (when the link is supposed to exist)

If VPS_SETUP.md was meant to live at the repo root and got lost, restore it. Don't fake it with a stub — empty stubs rot.

(c) Silence the check globally (last resort)

In documentation/.vitepress/config.mjs:

js
export default defineConfig({
  // ...
  ignoreDeadLinks: true,
})

You can also pass an array of patterns to ignore specific dead links rather than all of them. Don't reach for this first — it hides genuine link rot in the rest of the docs.

Why ​

The dead-link check is one of the few places where VitePress validates content rather than just rendering it. Disabling it without thinking turns a build error today into "every link in the site is broken" three months from now. Fix the link, don't fix the check.


2. Build prints The language 'caddy' is not loaded, falling back to 'txt' ​

Symptom ​

The language 'caddy' is not loaded, falling back to 'txt' for syntax highlighting.

The build still succeeds (unless it fails for another reason); the code block just renders without syntax colors.

Cause ​

VitePress uses Shiki for syntax highlighting. Shiki only knows the languages it ships with. caddy (and a handful of niche grammars) aren't in the default set — when a code fence is tagged ```caddy, Shiki can't highlight it and falls back to plain text.

Fix ​

Two options:

(a) Retag the code block with a close-enough language Shiki does know:

markdown
```nginx
# Caddyfile content goes here
```

For Caddyfiles, nginx is the usual stand-in — directive/value layout is similar enough that the colors aren't actively wrong.

(b) Register the language explicitly in .vitepress/config.mjs via the markdown.shikiSetup hook. This is more work and only worth it if you have a lot of Caddyfile snippets.

Why ​

This is a warning, not an error — leaving it alone is fine as long as you don't mind the un-coloured block. We mention it here because seeing it in the build output next to real errors makes the output look scarier than it is.


3. docs:dev shows Port 5173 is in use, trying another one... ​

Symptom ​

  vitepress v1.6.4

  ➜  Local:   http://localhost:5174/

The port shifted from 5173 to 5174 (or higher).

Cause ​

Another Vite process is already bound to 5173 — typically a forgotten docs:dev or npm run dev from the frontend project running in another terminal.

Fix ​

Either use the new port VitePress picked (it tells you in the output), or free 5173:

bash
# find and kill what's holding the port
lsof -i :5173       # macOS/Linux
ss -ltnp | grep 5173  # Linux alt

# Windows (PowerShell)
Get-NetTCPConnection -LocalPort 5173

Why ​

Vite auto-bumps the port to keep docs:dev non-blocking. There's no harm in running on 5174 — it's only worth chasing if you have bookmarks or a script hardcoded to 5173.


4. Sidebar entry missing for a new page ​

Symptom ​

You added guide/en/my-new-page.md, the dev server picks it up, but it doesn't show in the left sidebar.

Cause ​

VitePress doesn't auto-discover sidebar entries. Each page needs an entry in .vitepress/config.mjs. The file alone is enough for the page to render (direct URL works), but not to appear in the navigation.

Fix ​

Edit .vitepress/config.mjs and add the page under the right section of both the EN and FR sidebars:

js
{
  text: 'Infrastructure',
  items: [
    // ...
    { text: 'My new page', link: '/guide/en/my-new-page' }
  ]
}

Mirror the entry under /guide/fr/ so the bilingual structure stays in sync.

Why ​

Manual sidebar entries are a feature, not a bug — they let us order pages and group them semantically (Infrastructure, Scan, etc.) instead of dumping every file in alphabetical order. The cost is having to remember the two-step add: create the file and register it.