Skip to content

feat(fastify): actionable error when registered on unsupported Fastify version#8843

Open
h2m6jcm94s-eng wants to merge 1 commit into
clerk:mainfrom
h2m6jcm94s-eng:feat/fastify-version-mismatch-error
Open

feat(fastify): actionable error when registered on unsupported Fastify version#8843
h2m6jcm94s-eng wants to merge 1 commit into
clerk:mainfrom
h2m6jcm94s-eng:feat/fastify-version-mismatch-error

Conversation

@h2m6jcm94s-eng

@h2m6jcm94s-eng h2m6jcm94s-eng commented Jun 12, 2026

Copy link
Copy Markdown

Closes #8844.

Description

When @clerk/fastify is registered against Fastify < 5, the failure mode today is fastify-plugin's stock FST_ERR_PLUGIN_VERSION_MISMATCH. That error correctly identifies the mismatch but doesn't tell users what to do about it — and because Fastify 4 is still in LTS, this is a real footgun for teams that haven't migrated yet (and whose pnpm install warning got buried among other peer-dep noise). See #8844 for the full repro and motivation.

This PR replaces the stock error with a Clerk-branded one that spells out both resolution paths:

🔒 Clerk: @clerk/fastify requires fastify@>=5 but is being registered on fastify@4.28.0.

To resolve this, either:

  • upgrade your fastify dependency to ^5, or

  • pin @clerk/fastify@^1 to keep using fastify@4 (LTS):

    npm install @clerk/fastify@^1

    or: pnpm add @clerk/fastify@^1

I hit this firsthand while bootstrapping a Fastify 4 LTS app — the peer-dep warning at install time was easy to miss, and registration failed with the stock error which left me unsure whether to upgrade Fastify or downgrade @clerk/fastify.

Implementation

  • packages/fastify/src/clerkPlugin.ts — adds a major-version guard at the top of the plugin callback. The check is a one-line integer parse (^(\d+)) to avoid pulling semver for a single comparison.
  • The fastify: '5.x' field is removed from the fastify-plugin metadata so our actionable error wins instead of fastify-plugin's. Functionally identical outcome (registration fails on Fastify <5), better message.
  • packages/fastify/src/errors.ts — new incompatibleFastifyVersion(version) builder using the existing createErrorMessage helper so the 🔒 Clerk prefix and docs/discord links stay consistent.
  • packages/fastify/src/test/utils.tscreateFastifyInstanceMock accepts an optional { version } override; defaults to '5.8.5' so existing tests are unchanged.
  • packages/fastify/README.md — adds one note in the existing Prerequisites section explaining the @clerk/fastify@^1 pin path for Fastify 4 LTS users.
  • Changeset added (patch).

Tests

packages/fastify/src/__tests__/clerkPlugin.test.ts:

  • test.each(['4.28.0', '3.29.5', '2.0.0']) — verifies the error fires on multiple sub-5 versions, checks both the version mention and the pin guidance appear in the message, and confirms done() is never called.
  • test.each(['5.0.0', '5.8.5', '6.0.0-alpha.1']) — verifies normal registration on supported versions (and the open-ended ≥5 future-proofs against 6.x).

All 13 tests in clerkPlugin.test.ts pass locally (the rest of the suite fails on my machine because @clerk/backend workspace dep isn't built — should pass on CI where workspaces are pre-built).

Compatibility

  • No new dependencies.
  • No API changes for users on Fastify ≥5.
  • Behaviour for users on Fastify <5 changes from one error message to another (both fail at registration time, both are throws). No silent change.

…y version

When @clerk/fastify is registered on Fastify < 5, fastify-plugin's stock
`FST_ERR_PLUGIN_VERSION_MISMATCH` tells the user about the mismatch but
not how to resolve it. This makes the failure mode harder to act on than
it needs to be, especially because Fastify 4 is still LTS and many apps
have not migrated yet.

This change throws a Clerk-branded error at plugin registration time
that explicitly tells the user to either upgrade to fastify@^5 or pin
@clerk/fastify@^1 (which still supports Fastify 4 LTS).

The `fastify: '5.x'` field is removed from the fastify-plugin metadata
so our actionable error wins over fastify-plugin's stock one. The check
itself is a one-line integer comparison so no new dependencies are
introduced.

The README's Prerequisites section is updated to mention the
@clerk/fastify@^1 pin path for Fastify 4 LTS users.

Tests cover the throw on multiple sub-5 versions (4.28.0, 3.29.5, 2.0.0)
and confirm there is no throw on supported versions (5.0.0, 5.8.5,
6.0.0-alpha.1).

Signed-off-by: Devayan Dewri <287486912+h2m6jcm94s-eng@users.noreply.github.com>
@changeset-bot

changeset-bot Bot commented Jun 12, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 98734c9

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@clerk/fastify Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Jun 12, 2026

Copy link
Copy Markdown

@h2m6jcm94s-eng is attempting to deploy a commit to the Clerk Production Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR strengthens the Fastify plugin's version compatibility by moving from a static build-time constraint to runtime validation with actionable error guidance. The plugin now detects unsupported Fastify versions and returns a user-friendly message directing them to either upgrade Fastify to v5 or pin the package to v1 for Fastify 4 support.

Changes

Fastify Version Validation

Layer / File(s) Summary
Incompatible version error helper
packages/fastify/src/errors.ts
New incompatibleFastifyVersion(foundVersion) exports a formatted error message with upgrade and pin guidance for Fastify versions below 5.
Test mock version support
packages/fastify/src/test/utils.ts
createFastifyInstanceMock signature updated to accept optional overrides object, enabling version override for testing against different Fastify versions.
Runtime version checking in clerkPlugin
packages/fastify/src/clerkPlugin.ts
Plugin now parses Fastify major version from instance.version and throws incompatibleFastifyVersion error if < 5; static fastify: '5.x' constraint removed from plugin wrapper.
Version validation test coverage
packages/fastify/src/__tests__/clerkPlugin.test.ts
New test.each blocks validate error throw for Fastify < 5 and successful registration without throw for versions >= 5, with regex assertions on error message content.
User documentation and changeset
packages/fastify/README.md, .changeset/fastify-actionable-version-error.md
README adds compatibility note for Fastify 4 (LTS) users; changeset clarifies the new actionable error replacing the prior generic mismatch error.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

A rabbit hops to validate with care,
Fastify versions checked with messages fair,
"Upgrade to five!" or "pin version one,"
No cryptic errors—just solutions run. 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly describes the main change: implementing an actionable error message when @clerk/fastify is registered on unsupported Fastify versions.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/fastify/src/clerkPlugin.ts (1)

13-16: 💤 Low value

Consider adding explicit return type for clarity.

While parseFastifyMajor is an internal helper, adding an explicit return type (: number) would improve readability and align with TypeScript best practices.

📝 Suggested enhancement
-const parseFastifyMajor = (version: string): number => {
+const parseFastifyMajor = (version: string): number => {
   const match = /^(\d+)/.exec(version);
   return match ? Number.parseInt(match[1]!, 10) : 0;
 };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/fastify/src/clerkPlugin.ts` around lines 13 - 16, The helper
function parseFastifyMajor should have an explicit return type to improve
readability and TypeScript best practices; update the function signature for
parseFastifyMajor to declare its return type as number (e.g., ensure the arrow
function signature includes ": number") and keep the implementation converting
the matched group to a Number via Number.parseInt(match[1], 10) or returning 0
when no match.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/fastify/src/errors.ts`:
- Around line 20-29: The exported function incompatibleFastifyVersion currently
has no explicit return type; update its signature to include the correct return
type (the type returned by createErrorMessage, e.g., string or ErrorMessageType
used across the module) so the public API has an explicit annotation; locate the
incompatibleFastifyVersion declaration and add the appropriate return type
annotation matching createErrorMessage's return (or the module's convention) and
ensure export remains unchanged.

---

Nitpick comments:
In `@packages/fastify/src/clerkPlugin.ts`:
- Around line 13-16: The helper function parseFastifyMajor should have an
explicit return type to improve readability and TypeScript best practices;
update the function signature for parseFastifyMajor to declare its return type
as number (e.g., ensure the arrow function signature includes ": number") and
keep the implementation converting the matched group to a Number via
Number.parseInt(match[1], 10) or returning 0 when no match.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 5d1636ca-d12f-4a7f-a461-1b737bf85531

📥 Commits

Reviewing files that changed from the base of the PR and between 8744728 and 98734c9.

📒 Files selected for processing (6)
  • .changeset/fastify-actionable-version-error.md
  • packages/fastify/README.md
  • packages/fastify/src/__tests__/clerkPlugin.test.ts
  • packages/fastify/src/clerkPlugin.ts
  • packages/fastify/src/errors.ts
  • packages/fastify/src/test/utils.ts

Comment on lines +20 to +29
export const incompatibleFastifyVersion = (foundVersion: string) =>
createErrorMessage(`@clerk/fastify requires fastify@>=5 but is being registered on fastify@${foundVersion}.

To resolve this, either:
- upgrade your fastify dependency to ^5, or
- pin @clerk/fastify@^1 to keep using fastify@4 (LTS):

npm install @clerk/fastify@^1
# or: pnpm add @clerk/fastify@^1
`);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add explicit return type annotation for the exported function.

The exported function incompatibleFastifyVersion lacks an explicit return type. As per coding guidelines, all exported functions (especially public APIs) should define explicit return types for better type safety and API clarity.

📝 Proposed fix
-export const incompatibleFastifyVersion = (foundVersion: string) =>
+export const incompatibleFastifyVersion = (foundVersion: string): string =>
   createErrorMessage(`@clerk/fastify requires fastify@>=5 but is being registered on fastify@${foundVersion}.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const incompatibleFastifyVersion = (foundVersion: string) =>
createErrorMessage(`@clerk/fastify requires fastify@>=5 but is being registered on fastify@${foundVersion}.
To resolve this, either:
- upgrade your fastify dependency to ^5, or
- pin @clerk/fastify@^1 to keep using fastify@4 (LTS):
npm install @clerk/fastify@^1
# or: pnpm add @clerk/fastify@^1
`);
export const incompatibleFastifyVersion = (foundVersion: string): string =>
createErrorMessage(`@clerk/fastify requires fastify@>=5 but is being registered on fastify@${foundVersion}.
To resolve this, either:
- upgrade your fastify dependency to ^5, or
- pin `@clerk/fastify`@^1 to keep using fastify@4 (LTS):
npm install `@clerk/fastify`@^1
# or: pnpm add `@clerk/fastify`@^1
`);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/fastify/src/errors.ts` around lines 20 - 29, The exported function
incompatibleFastifyVersion currently has no explicit return type; update its
signature to include the correct return type (the type returned by
createErrorMessage, e.g., string or ErrorMessageType used across the module) so
the public API has an explicit annotation; locate the incompatibleFastifyVersion
declaration and add the appropriate return type annotation matching
createErrorMessage's return (or the module's convention) and ensure export
remains unchanged.

Source: Coding guidelines

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

@clerk/fastify: silent peer-dep warning when host is on Fastify 4 leads to an unclear FST_ERR_PLUGIN_VERSION_MISMATCH at registration time

1 participant