🐛 Fixed themes with custom error templates returning HTTP 500#28779
🐛 Fixed themes with custom error templates returning HTTP 500#28779sagzy wants to merge 1 commit into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
WalkthroughThe error handler middleware ( 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
|
| Command | Status | Duration | Result |
|---|---|---|---|
nx run ghost:test:ci:integration |
✅ Succeeded | 2m 9s | View ↗ |
nx run ghost:test:ci:integration:no-coverage |
✅ Succeeded | 2m 9s | View ↗ |
nx run ghost:test:ci:e2e |
✅ Succeeded | 7m 48s | View ↗ |
nx run ghost:test:ci:e2e:no-coverage |
✅ Succeeded | 6m 33s | View ↗ |
nx build @tryghost/activitypub |
✅ Succeeded | 3s | View ↗ |
nx build @tryghost/portal |
✅ Succeeded | 1s | View ↗ |
nx build @tryghost/comments-ui |
✅ Succeeded | <1s | View ↗ |
nx build @tryghost/signup-form |
✅ Succeeded | <1s | View ↗ |
Additional runs (10) |
✅ Succeeded | ... | View ↗ |
💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗
☁️ Nx Cloud last updated this comment at 2026-06-22 14:49:19 UTC
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3bc5acbbaf
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
3bc5acb to
2ea377b
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@ghost/core/core/frontend/web/middleware/error-handler.js`:
- Around line 112-115: The condition checking `_.isEmpty(req.app.engines)` is
too broad and will prevent the `hbs` engine from being registered if any other
engine is already registered. Instead of checking if the engines object is
empty, specifically check whether the `hbs` engine exists in `req.app.engines`
before calling `createHbsEngine()`. Replace the isEmpty check with a condition
that explicitly verifies if the `hbs` engine is not already registered (for
example, checking if `req.app.engines.hbs` is undefined or falsy), and only
proceed with engine registration if that specific check passes.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 731c863b-12a7-42b2-8843-57512bbace04
📒 Files selected for processing (2)
ghost/core/core/frontend/web/middleware/error-handler.jsghost/core/test/unit/frontend/web/middleware/error-handler.test.js
no ref - frontend errors thrown before the theme middleware mounts the active theme (errors early in the request pipeline, or the first requests after a boot) reached the error renderer with the theme not yet mounted - in that state the renderer picked a theme-specific error template name (e.g. error-404) from the theme's manifest, but Express resolved it against Ghost's default views directory — where it does not exist — producing `Failed to lookup view "error-404"` and an HTTP 500 instead of the theme's error page - the bare-minimum fallback also permanently repointed the app's `views` directory to the default, so once armed it could keep masking real status codes (e.g. a 404) as 500s until a normal request mounted the theme - now, when the active theme isn't mounted, we render Ghost's self-contained built-in error template — its engine, views dir and the @site/@custom/ member template data that theme error pages rely on aren't set up yet — and only render theme error templates when the theme is genuinely mounted - the fallback references the built-in template by absolute path instead of mutating the app-wide views directory, so it can no longer break theme template lookups on subsequent requests Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2ea377b to
fa9c2c8
Compare

Summary
Frontend requests that errored before the theme middleware mounted the active theme — errors thrown early in the request pipeline, or the first requests after a boot/restart — reached the theme error renderer with the theme not yet mounted into Express.
In that state:
setTemplateselected a theme-specific error template name (e.g.error-404) by consulting the theme's in-memory manifest (hasTemplate), independent of Express's configured views directory.But
res.render('error-404', …)resolved that name against Ghost's default views directory (core/server/views/), which only contains a genericerror.hbs— producing:…and an HTTP 500 instead of an error page.
The bare-minimum fallback guard (
if (_.isEmpty(req.app.engines))) also permanently repointed the app's globalviewsdirectory to the default and registered a minimal engine. It only ran once (afterwardsapp.enginesis non-empty, so it's skipped), so once armed it could keep masking real status codes (e.g. a genuine404) as500s until a normal request finally mounted the theme — which is why this clustered right after restarts/deploys. Themes shipping only a genericerror.hbsdidn't hit the lookup failure, because the nameerroralso exists in the default views dir — so this surfaced specifically for themes with templates likeerror-404.hbs.Fix
When the active theme isn't mounted, the error renderer now renders Ghost's self-contained built-in error template rather than a theme template. Rendering a theme error page requires more than the right views dir — it needs the full theme engine and the per-request/global template data (
@site,@custom,member, …) thatupdate-global-template-options/update-local-template-optionspopulate during the normal pipeline. None of that is set up in the pre-mount window, so a themed error page there would render with broken/missing data (and could throw in{{ghost_head}}/{{#get}}). Theme error templates are now only rendered when the theme is genuinely mounted — the existing, working path where that data is already in place.The built-in template is also referenced by absolute path instead of via
req.app.set('views', defaultViews), so the fallback can no longer repoint the app-wide views directory and break theme template lookups on later requests.Testing
Added regression tests in
error-handler.test.jsdriving the realthemeErrorRendererover the post-boot/pre-mount sequence:error-404renders the built-in template (not a 500) when unmounted.viewsdir (the exact reproduction of the reported bug).views.Verified the two behavioural regression tests fail against the original code and pass with this change. Full
ghost/corefrontend unit suite (1889 tests) and lint are green.🤖 Generated with Claude Code