Skip to content

Fix bad links and link checker errors#2324

Open
krzysdz wants to merge 16 commits into
expressjs:mainfrom
krzysdz:fixing-links
Open

Fix bad links and link checker errors#2324
krzysdz wants to merge 16 commits into
expressjs:mainfrom
krzysdz:fixing-links

Conversation

@krzysdz
Copy link
Copy Markdown
Contributor

@krzysdz krzysdz commented May 18, 2026

@netlify
Copy link
Copy Markdown

netlify Bot commented May 18, 2026

Deploy Preview for expressjscom-preview ready!

Name Link
🔨 Latest commit 90106fd
🔍 Latest deploy log https://app.netlify.com/projects/expressjscom-preview/deploys/6a1a0f1db0460300081262ed
😎 Deploy Preview https://deploy-preview-2324--expressjscom-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 99 (🟢 up 2 from production)
Accessibility: 100 (no change from production)
Best Practices: 100 (no change from production)
SEO: 100 (no change from production)
PWA: 80 (no change from production)
View the detailed breakdown and full score reports
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Copy Markdown
Member

@jonchurch jonchurch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This LGTM as a first pass, the slack 403 is really noisey and we should fix that asap

I dont see any failures on the linkedin share-offsite popping up in the logs though

@jonchurch
Copy link
Copy Markdown
Member

I parsed through the link checker output w/ claude, and after excluding the slack invite ones, this is the report I had it generate w/ the current failures:

Lychee follow-ups

After this PR removes the slack-invite noise (1,221 of 1,608 errors), the remaining 387 are real. Tracking the unique URLs and source locations so they can be split into follow-up PRs.

Bucket 1 — English-source bugs (each appears 10×, once per locale)

These are the highest-leverage fixes: one source edit clears ~10 errors.

  • app-set#app.settings.table (50× total) — broken anchor link in src/content/api/{4x,5x}/api/request/index.mdx. Should reference the app.set() anchor on the application page.
  • api/application/app-settings (30× total) — broken link in src/content/api/{4x,5x}/api/response/index.mdx. Missing version + locale prefix.
  • 5x/api/application/app-settings (20× total) — broken link in src/content/api/5x/api/application/index.mdx.
  • /guide/resources/middleware relative-link bug — in src/content/docs/en/{4x,5x,unversioned}/guide/using-middleware.mdx. Should be absolute (/en/resources/middleware/).
  • <https://msdn.microsoft.com/...> angle-bracket URL escaping — in src/content/docs/en/advanced/best-practice-security.md. Parens in the URL plus markdown angle-bracket autolink syntax confuse the parser.

Bucket 2 — External link rot / Node.js docs URL pattern changes

  • Node.js docs anchors moved (~50× total) in src/content/docs/en/advanced/best-practice-performance.mdx and src/content/docs/en/{4x,5x}/guide/debugging.mdx:
    • nodejs.org/api/util#util_util_inspect_object_options#utilinspectobject-options
    • nodejs.org/api/process#process_event_uncaughtexception#event-uncaughtexception
    • nodejs.org/api/cli#cli_trace_sync_io#--trace-sync-io
    • nodejs.org/api/console#console#console
    • nodejs.org/api/cluster and nodejs.org/api/domain → check current paths
  • nginx.org 404s (20× total) in best-practice-performancenginx.org/en/docs/http/{ngx_http_gzip_module,load_balancing} need updated URLs
  • freedesktop.org/.../systemd.unit 404 — check current docs URL
  • expressjs.com/guide/error-handling.html (10×) in src/content/pages/en/resources/middleware/multer.md — old .html URL format
  • expressjs.com/en/guide/behind-proxies.html (9×) in src/content/pages/en/resources/middleware/cookie-session.md — same issue
  • famfamfam.com + /lab/icons/silk/ in resources/middleware/serve-index.md — domain dead, find replacement
  • sequelizejs.com in resources/middleware/session.md — domain moved to sequelize.org
  • cyclic.sh in resources/middleware/session.md — service shut down, remove
  • mysql.com / oracle.com in resources/middleware/session.md — bot-blocked but URLs work in browser

Bucket 3 — False positives worth ignoring in CI

  • linkedin.com/in/* profile URLs (20× across 2 URLs) in src/content/blog/2026-05-18-a-new-look-for-express.md — LinkedIn 999s bot traffic on profile views. Lychee maintainers recommend --accept 200..=299,999 in workflow args (see Handle unknown status codes lycheeverse/lychee#234).
  • localhost:3000 (10×) in src/content/docs/en/guide/migrating-4.mdx — example URL, not a real link. Either add --exclude '^http://localhost' to args or use a placeholder format.

Bucket 4 — Translation pipeline bugs (Crowdin)

Translators are translating URL slugs as if they were prose. Per-locale broken links:

  • de: ressourcen/{beitragen,Gemeinschaft,Glossar,utils} — German slugs instead of canonical English
  • es: recursos/{comunidad,contribuyendo,glosario,middleware,utils}
  • fr: ressources/{communauté,contribution,glossaire} + 5 logo image paths that don't exist
  • it: resources/{contributor,glossario}
  • ja: resources/contribution
  • pt-br (worst): links to pt/resources/{community,glossário,middleware,utils} — wrong locale prefix entirely
  • pt-br: resources/middleware/cors has literal `http:/example.com"`` — markdown got mangled in translation
  • ja: developer.mozilla.org/...Cross-site_scripting%EF%BC%89... — MDN anchor with Japanese-translated text appended

Crowdin treats href="" values as translatable strings. Two paths forward:

  1. Configure Crowdin to mark URL attributes as non-translatable (its "do-not-translate" / placeholder feature)
  2. Source-side: replace hardcoded href="/de/resources/X" with JS expressions like href={/${lang}/resources/X} so URLs are generated, not translated

Coverage math

Bucket Errors after this PR Effort
1 — English-source bugs ~140 low — single-line edits
2 — Link rot ~110 medium — needs verification of replacement URLs
3 — False positives ~30 low — workflow tweak
4 — Translation slugs ~30 high — Crowdin config + cleanup pass
Total real signal ~310

@krzysdz
Copy link
Copy Markdown
Contributor Author

krzysdz commented May 19, 2026

I dont see any failures on the linkedin share-offsite popping up in the logs though

I knew I saw it somewhere. The commit that ignores it is almost a month old, but I have rebased the branch last night.

https://github.com/expressjs/expressjs.com/actions/runs/24803825545/job/72593188466#step:4:115

Screenshot_2026-05-19-07-32-03-763_org mozilla fenix

@krzysdz krzysdz changed the title [WIP] Fix link checker errors [WIP] Fix bad links and link checker errors May 19, 2026
@krzysdz krzysdz force-pushed the fixing-links branch 5 times, most recently from 1484381 to 9cc6f6c Compare May 21, 2026 00:53
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should links in non-versioned files like this lead to non-versioned API (that renders the "default version") or be hardcoded to a specific version (or maybe it is possible to use a parameter that will reference the latest/default version - e.g. ../../{{ DEFAULT_VERSION }}/api/express)?

## Don't use deprecated or vulnerable versions of Express

Express 2.x and 3.x are no longer maintained. Security and performance issues in these versions won't be fixed. Do not use them! If you haven't moved to version 4, follow the [migration guide](/en/guide/migrating-4) or consider [Commercial Support Options](/en/support#commercial-support-options).
Express 2.x and 3.x are no longer maintained. Security and performance issues in these versions won't be fixed. Do not use them! If you haven't moved to version 4, follow the [migration guide](../../guide/migrating-4) or consider [Commercial Support Options](../../support#commercial-support-options).
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if the "Security best practices" docs should suggest updating to Express 4 (released 12 years ago), when Express 5 has been marked as latest for over a year.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be outdated. I know that recent security updates have been announced in blog posts, but I think it would be good to either update this page or at least direct visitors to the blog.

Comment thread src/content/pages/en/guide/migrating-4.mdx
@krzysdz
Copy link
Copy Markdown
Contributor Author

krzysdz commented May 21, 2026

It seems that relative links are not a great idea. While these are easier to run search&replace across versions and do not require changes in translations, it turns out that there are some docs (e.g. guides, but also /en/api/) available under both versioned (https://expressjs.com/en/5x/starter/installing/) and non-versioned (https://expressjs.com/en/starter/installing/) paths.
These non-versioned docs render files from 5x directories, but because the path is shorter, some relative links (that assume version in URL) break. While investigating it, I have noticed that versioned pages load with the menu open, but non-versioned do not. The menu also does not reflect the "category" (Docs, API) if the URL points to a non-versioned page that uses a versioned (5x) fallback.

I can change only the links that cause errors, but I'd like to be consistent.

@bjohansebas @jonchurch do you have any thoughts on this?

krzysdz added 9 commits May 28, 2026 16:15
Internal links have been changed to relative URLs. This should help with redirecting to translated pages (the URL won't have to be localized) and keeping the right version.
Anchors that point to headers that are localized will have to be changed.
- a few HTTP -> HTTPS
- some were updated to the URLs that they redirect to
- a few had `#` anchors updated
- fixed some doc URLs that have moved (Node.js, nginx, systemd)
- things that I could not find an up-to date link for, have been changed to Internet Archive links
- one link to an example of unsupported product has been removed (closes expressjs#2270)
This means that other translations will require replacing `/en/` with the appropriate language code and when a new version is released, links in copied documentation will have to be updated.

Unfortunately, this is required for unversioned pages that load the latest API/guides to work, unless I can figure out how to use templates in `*.mdx` and pass values when rendering them from `*.astro`
krzysdz added 3 commits May 29, 2026 11:55
One of the guide pages (migrating to Express 4) linked to localhost, so that it would be easier for people to open their website and check if it works
@bjohansebas
Copy link
Copy Markdown
Member

@bjohansebas @jonchurch do you have any thoughts on this?

for links see #2193 so i18n is no broken

@krzysdz krzysdz marked this pull request as ready for review May 29, 2026 20:45
@krzysdz krzysdz requested review from a team as code owners May 29, 2026 20:45
@krzysdz
Copy link
Copy Markdown
Contributor Author

krzysdz commented May 29, 2026

The internal links somewhat inconsistently use trailing /. I can change them to one version if we decide whether we want #2356.

@krzysdz krzysdz added bug docs Issues/pr concerning content github_actions Pull requests that update GitHub Actions code labels May 29, 2026
@krzysdz krzysdz changed the title [WIP] Fix bad links and link checker errors Fix bad links and link checker errors May 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug docs Issues/pr concerning content github_actions Pull requests that update GitHub Actions code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Links to query parser settings page broken Broken link to "Third-party middleware" page in Express docs 404 page in Additional examples

3 participants