> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Glossary internal links that 404

> A reader clicks a link into the public glossary and lands on a 404 — the link names a term slug the registry does not ship. Diagnose the three shapes that produce it, and gate every publish with the slug-diff checklist.

# Glossary internal links that 404

The public glossary ([orbit.devotel.io/en/glossary](https://orbit.devotel.io/en/glossary))
renders every term from one registry, so a link to `/glossary/<slug>` only
resolves while that slug is in the registry. When a reader clicks a
glossary link somewhere in the product or marketing surface and hits a 404,
the link names a slug the registry does not contain — a broken internal
link, not a service fault.

This page covers exactly that failure class: a glossary link that resolves
to a 404. If instead the whole glossary segment fails to render (blank
page, generic server error), that is the route-level fault class — not
this page.

## Symptoms

* Clicking a link that points at `/glossary/<slug>` returns a **404 Not
  Found** instead of the term definition.
* The browser console logs the 404 on the document request (no redirect,
  no retry — a hard miss against `generateStaticParams`).
* The glossary index at `/glossary` loads fine; only the specific term
  page is missing.
* A link-checker or crawler flags the URL as broken; the destination slug
  never existed as a published term, or it was renamed/removed after the
  link went in.

<Note>
  The 404 is deterministic. The term route generates its static params from
  the registry at build time, so an unlisted slug misses on every request —
  there is no transient class and no retry that clears it.
</Note>

## Why a glossary link can 404

<AccordionGroup>
  <Accordion title="The link names a slug that was never published">
    The writer typed a plausible-sounding term slug by hand — a guess at the
    naming — and no term file ever shipped with that exact slug. The click
    404s because the registry has no such term.

    **Offender class:** any hard-coded `/glossary/<slug>` string in page or
    component source, landing copy, or email content — for example a link
    into the registry living beside the term files. Find it with:

    ```bash theme={null}
    grep -rno '/glossary/[a-z0-9-]*' apps/web/src
    ```

    Map each match to a term the registry actually ships. The offender file
    is whichever one carries the bad literal. The guard that prevents this
    class from shipping is the registry test
    `glossary-enonly-surface.test.ts` (it resolves cross-references inside
    the registry against the full slug set), plus the pre-publish checklist
    below for links outside the registry itself.
  </Accordion>

  <Accordion title="The term was renamed or removed, the link was not">
    Every glossary URL routes from the term's `slug` field. A rename
    (`hlr` → `hlr-lookup`), a slug cleanup (`dkim` → `dkim-signature`), or a
    consolidation of two near-duplicate terms leaves any published link
    naming the old slug with a permanent 404.

    **Offender class:** a committed link whose destination slug points at a
    `slug` value that no longer exists anywhere in the registry. To find the
    offender file, grep the repo for the old slug:

    ```bash theme={null}
    grep -rn "/glossary/your-old-slug" apps/web/src
    ```

    The fix is to point the link at the term's current slug, or to the
    glossary index if the term no longer exists. The same registry test
    `glossary-enonly-surface.test.ts` that keeps in-registry cross-links
    resolving also blocks a rename from silently orphaning the links other
    terms carry — apply the same discipline to any page-level link you write.
  </Accordion>

  <Accordion title="The slug pattern is valid but the registry filter rejected it">
    A glossary slug must match `[a-z0-9-]` and be unique in the registry. A
    link built from a template (`/glossary/${term}`) interpolates whatever
    value it is handed — if the value contains an uppercase letter, an
    underscore, or a trailing hyphen, the slug pattern never matches, so the
    route never publishes it and the link 404s no matter what.

    **Offender class:** a programmatic link built with an unchecked string
    (e.g. the raw term title instead of the `slug` field), or a slug value
    that slipped past the pattern guard at author time.

    The registry test
    `glossary-enonly-surface.test.ts` rejects a non-conforming slug at
    registry-load time — this is why the registry itself stays clean; the
    checklist below extends the same check to editorial links you write
    outside the registry.
  </Accordion>
</AccordionGroup>

## Why this page exists

`reference/troubleshooting-hub.mdx` is the catalogued index of every
runbook, but before this page shipped there was no runbook that caught
the failure class "we published a glossary link that 404s" — it only
indexed fault classes on live APIs, not this editorial/publish-side one.
File this page under the hub's **Everything else** section so the
discovery index owns it alongside the misc runbooks, and so the next
reader who hits a glossary 404 finds a remediation path rather than a
dead link.

## Pre-publish checklist

Run this whenever you add or edit a glossary link in product or marketing
source — it is the only reliable gate for the class above.

1. **Extract the slugs your links name.** From the repo root, list every
   distinct slug a link points to:

   ```bash theme={null}
   grep -rno '/glossary/[a-z0-9-]*' apps/web/src/lib/glossary/terms/*.ts \
     | sed 's|.*:/glossary/||' \
     | sort -u > /tmp/linked-slugs.txt
   ```

2. **List the slugs the registry actually ships.** One term file owns one
   slug — the file names are the slug inventory:

   ```bash theme={null}
   ls apps/web/src/lib/glossary/terms/ \
     | sed 's|\.ts$||' \
     | grep -v '^index$' \
     | sort -u > /tmp/registry-slugs.txt
   ```

3. **Diff the two sets.** Anything a link names but the registry does not
   ship is a broken link that would 404:

   ```bash theme={null}
   comm -23 /tmp/linked-slugs.txt /tmp/registry-slugs.txt
   ```

   An empty result means every checked slug resolves. A non-empty row is
   the offender — open the file the first grep named and fix the literal.

4. **Include the inline registry, not just the per-file inventory.** Some
   terms still live inline in the `terms.ts` register (the migration of
   `MIGRATED_TERMS` to per-file modules is staged, so the inventory of
   files is not the whole registry). When a slug is reported missing and
   `ls` disagrees, check whether it is in the inline register before
   treating the link as broken:

   ```bash theme={null}
   grep -o 'slug: *"[^"]*"' apps/web/src/lib/glossary/terms.ts \
     | sed 's/slug: *"//;s/"$//' \
     | sort -u
   ```

5. **Re-run the registry test before you ship.** The
   `glossary-enonly-surface.test.ts` pin asserts the in-registry
   cross-links resolve; the checklist above extends that guarantee to the
   links you authored outside the registry itself. Do not publish a
   glossary link without both passing.

<Note>
  The checklist is about editorial links you personally add. The registry
  itself is already guarded — the en-only surface test reports a broken
  slug at build time, so what you write outside the registry is the only
  surface a click can 404 on.
</Note>

## What to send support

If a glossary link from a Devotel-published surface 404s, or the
checklist above flags a slug you cannot reconcile, open a ticket with:

* The URL that 404s (the full `/en/glossary/<slug>` path).
* The surface you clicked it from (dashboard page, docs page, email).
* The offender file and the row the `comm` output above returned, if you
  ran the checklist.

## See also

* [Troubleshooting hub](/reference/troubleshooting-hub) — every runbook
  by failure class.
* [Error codes reference](/reference/error-codes) — for a 4xx envelope
  from a live API (not a 404 page miss).
