Skip to content

Fixed /gift returning HTTP 404#27912

Merged
sagzy merged 1 commit into
mainfrom
gift-subscriptions/preview-link-fix
May 15, 2026
Merged

Fixed /gift returning HTTP 404#27912
sagzy merged 1 commit into
mainfrom
gift-subscriptions/preview-link-fix

Conversation

@sagzy
Copy link
Copy Markdown
Contributor

@sagzy sagzy commented May 15, 2026

ref https://linear.app/ghost/issue/BER-3662

Summary

Gift subscription redemption links live at /gift/<token>. The sub-app at ghost/core/core/server/web/gift-preview/ is mounted via frontendApp.lazyUse('/gift', ...) and currently captures every /gift* request — including the bare /gift and /gift/, which fall through to errorHandler.pageNotFound and produce a 404. That makes it impossible for a site owner to use /gift as a navigation link backed by a custom Ghost page or routes.yaml entry.

This PR removes the two terminating error-handler middlewares (and their now-unused imports) from the gift-preview sub-app. Tokenless requests now fall through into Ghost's normal frontend routing, where:

  • a Ghost page with slug gift renders if one exists,
  • a routes.yaml entry for /gift/ is honored if one exists,
  • otherwise Ghost's standard themed 404 is served (same as any other unconfigured path).

The token-bearing redemption flow (/gift/<token>, /gift/<token>/image) is untouched.

Why this is safe

  • Both controllers (giftPreview, giftPreviewImage) handle their own errors via try/catch and never propagate, so the sub-app's HTML error-handling stack was a dead path for any real request.
  • shared/express.js already auto-registers sentry.errorHandler as the first error middleware on every sub-app, so removing the explicit handleHTMLResponse(sentry) does not drop Sentry coverage.
  • Route patterns /:token and /:token/image still match tokened requests first, so the existing redemption and OG-image flows are byte-identical.

Test plan

  • Existing unit tests in test/unit/server/web/gift-preview/controller.test.js still pass (controller is unchanged).
  • New e2e-frontend smoke test in test/e2e-frontend/default-routes.test.js:
    • Creates a page with slug gift and asserts GET /gift/ returns 200 with that page's title — proves the sub-app no longer intercepts tokenless requests.
    • Asserts GET /gift/<unknown-token> still returns a 302 redirect to the homepage (existing controller fallback for invalid tokens — regression guard).
  • pnpm lint:server and pnpm lint:test clean.

Manual verification

With pnpm dev running and the giftSubscriptions lab flag enabled:

  • GET /gift/<valid-token> → 200 HTML with meta-refresh to /#/portal/gift/redeem/<token> (unchanged)
  • GET /gift/<invalid-token> → 302 to homepage (unchanged)
  • GET /gift/<valid-token>/image → 200 PNG (unchanged)
  • GET /gift with no /gift page configured → themed Ghost 404 (was: bare sub-app 404)
  • GET /gift/ with a custom page at slug gift → that page renders (was: 404)

- gift redemption links live at /gift/<token>, but a bare /gift or /gift/ (e.g. a site navigation link) hit the gift-preview sub-app and were terminated with a 404 by errorHandler.pageNotFound
- the sub-app should only handle tokened requests; tokenless ones need to fall through to Ghost's regular frontend routing so a custom page (or routes.yaml entry) at /gift/ can render normally, or Ghost's themed 404 takes over
- the controllers handle their own errors internally, and shared/express.js auto-registers sentry.errorHandler on every sub-app, so removing the trailing pageNotFound + handleHTMLResponse middlewares is safe
- added an e2e-frontend smoke test that creates a page with slug 'gift' and asserts it renders at /gift/, plus a regression guard that /gift/<bad-token> still 302-redirects to the homepage

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 15, 2026

Review Change Stack

Walkthrough

This PR simplifies the gift-preview Express app by removing error handling middleware registrations (error-handler middleware and Sentry HTML error responses). The app now returns immediately after route setup without the previous error handling pipeline. Corresponding integration tests were added to verify that /gift/ renders a custom page and /gift/<invalid-token> produces the expected redirect behavior.

Suggested reviewers

  • mike182uk
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 The pull request description clearly explains the change: removing error-handler middlewares from the gift-preview sub-app so tokenless requests fall through to Ghost's normal frontend routing, with detailed rationale, test plan, and manual verification steps.
Title check ✅ Passed The title 'Fixed /gift returning HTTP 404' directly addresses the main change: removing error-handler middlewares to prevent tokenless /gift requests from returning 404, allowing them to fall through to normal frontend routing.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch gift-subscriptions/preview-link-fix

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

@sagzy sagzy changed the title 🐛 Fixed /gift returning 404 when no token is provided Fixed /gift returning 404 May 15, 2026
@sagzy sagzy changed the title Fixed /gift returning 404 Fixed /gift returning HTTP 404 May 15, 2026
@sagzy sagzy changed the title Fixed /gift returning HTTP 404 Fixed /gift/ returning HTTP 404 May 15, 2026
@sagzy sagzy changed the title Fixed /gift/ returning HTTP 404 Fixed /gift returning HTTP 404 May 15, 2026
@sagzy sagzy merged commit fe8acc8 into main May 15, 2026
44 checks passed
@sagzy sagzy deleted the gift-subscriptions/preview-link-fix branch May 15, 2026 14:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant