Skip to content

[recovery] fix(date): normalize whitespace in formatDate to prevent hydration mismatch - #19191

Draft
ethorg-agent-code[bot] wants to merge 1 commit into
devfrom
recovery/fix/format-date-hydration-whitespace
Draft

[recovery] fix(date): normalize whitespace in formatDate to prevent hydration mismatch#19191
ethorg-agent-code[bot] wants to merge 1 commit into
devfrom
recovery/fix/format-date-hydration-whitespace

Conversation

@ethorg-agent-code

Copy link
Copy Markdown

Production error

  • Message: Error: Hydration failed because the server rendered text didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used:
  • URL / culprit: /:locale/latesthttps://ethereumorg-ow.sentry.io/issues/7704895191/
  • Occurrences: 9 events since first seen 2026-09-01T15:42:26Z

Root cause

app/[locale]/latest/_components/LatestArticlesGrid.tsx is a "use client" component that's SSR'd on the /latest page. It calls formatDate(article.date, locale, { month: "short" }) directly during render for each card's date label.

formatDate (in src/lib/utils/date.ts) formats via Intl.DateTimeFormat but did no whitespace normalization. Node's ICU and a browser's ICU can render the same date with different space characters around date parts (e.g. U+202F narrow no-break space vs a regular U+0020) depending on locale/platform. Those differ byte-for-byte even though they look identical, which trips React's hydration text-mismatch check when the component re-renders on the client after SSR.

This exact class of bug was already fixed once in this file: formatDateRange normalizes whitespace with .replace(/\s+/g, " ") and has a comment explaining precisely this Node-vs-browser ICU divergence. formatDate — used by the same /latest client component — never got the equivalent fix.

Fix

Applied the same whitespace-normalization step to formatDate that formatDateRange already uses, with a comment cross-referencing it, so the two stay in sync going forward. Single-file change, no behavior change to the rendered text itself (only collapses different whitespace characters to a plain space).

Verification

  • pnpm type-check — passed
  • pnpm exec eslint src/lib/utils/date.ts — clean (no errors/warnings)

…smatch

formatDateRange already normalizes whitespace to work around Node vs
browser ICU differences (narrow no-break space vs regular space) that
otherwise trip React's hydration check. formatDate never got the same
fix, and is called directly during render by LatestArticlesGrid, a
client component SSR'd on /latest, causing hydration mismatches for
locales/browsers where ICU output differs.
@ethorg-agent-code ethorg-agent-code Bot added the recovery-agent Created by the Recovery Agent label Sep 1, 2026
@netlify

netlify Bot commented Sep 1, 2026

Copy link
Copy Markdown

Deploy Preview for ethereumorg ready!

Name Link
🔨 Latest commit dd52939
🔍 Latest deploy log https://app.netlify.com/projects/ethereumorg/deploys/6a97054c49b02200086dc496
😎 Deploy Preview https://deploy-preview-19191.ethereum.it
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
7 paths audited
Performance: 62 (🔴 down 3 from production)
Accessibility: 96 (no change from production)
Best Practices: 100 (🟢 up 1 from production)
SEO: 98 (no change from production)
PWA: 60 (no change from production)
View the detailed breakdown and full score reports

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

recovery-agent Created by the Recovery Agent tooling 🔧 Changes related to tooling of the project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants