Skip to content

fix: contain HttpError within sections instead of crashing the entire page#1152

Open
nicacioliveira wants to merge 1 commit intomainfrom
fix/contain-http-errors-in-sections
Open

fix: contain HttpError within sections instead of crashing the entire page#1152
nicacioliveira wants to merge 1 commit intomainfrom
fix/contain-http-errors-in-sections

Conversation

@nicacioliveira
Copy link
Copy Markdown
Contributor

@nicacioliveira nicacioliveira commented Apr 4, 2026

Problem

When a section's loader throws an HttpError (e.g., 429 Too Many Requests or 500 Internal Server Error from upstream APIs like VTEX), the error propagates through three layers and crashes the entire page instead of being contained within the affected section:

  1. blocks/loader.tswrapCaughtErrors: catches errors but re-throws HttpError
  2. blocks/section.ts — section resolver .catch(): catches errors but re-throws HttpError
  3. components/section.tsxErrorBoundary.getDerivedStateFromError: catches errors but re-throws HttpError

This means a single failing section (e.g., a ProductShelf showing related products) makes the entire page return the upstream error status code.

Real-world impact (production incidents)

We observed this across multiple production sites:

Site Error Cause
lumini (lojavirtual.lumini.com.br) HttpError 429: Too Many Requests VTEX rate limiting on relatedProductsLoader
lumini SyntaxError: Unterminated string in JSON Corrupted API response cached by staleWhileRevalidate
hectornew (www.hectoralbertazzi.com.br) HttpError 429: Too Many Requests VTEX rate limiting on relatedProductsLoader
petfarma (www.petfarma.com) TypeError: Cannot destructure property 'products' Loader not resolving props for /offline page

Cloudflare healthchecks hit the home page, receive a 404/429 (from a single section's loader failure), and mark the site as Unhealthy — even though the pod is running fine and the page would render correctly if the failing section was contained.

Error flow (before this fix)

VTEX API returns 429
  → fetchSafe throws HttpError(429)
  → wrapCaughtErrors: "it's HttpError, re-throw!"
  → section.ts .catch: "it's HttpError, re-throw!"
  → ErrorBoundary: "it's HttpError, re-throw!"
  → HTTP handler returns 429 for the ENTIRE page
  → Cloudflare healthcheck sees 429 → marks site Unhealthy

Error flow (after this fix)

VTEX API returns 429
  → fetchSafe throws HttpError(429)
  → wrapCaughtErrors: wraps in error Proxy
  → section.ts .catch: wraps with alwaysThrow → ErrorBoundary
  → ErrorBoundary: catches error → renders ErrorFallback for that section only
  → Page returns 200 with the failing section showing its fallback
  → Cloudflare healthcheck sees 200 → site stays Healthy

Changes

  • blocks/loader.ts: Remove HttpError re-throw in wrapCaughtErrors — treat all errors the same way (wrap in error Proxy)
  • blocks/section.ts: Remove HttpError re-throw in section resolver .catch() — let all errors go through the ErrorBoundary path
  • components/section.tsx: Remove HttpError re-throw in ErrorBoundary.getDerivedStateFromError — contain all errors and render ErrorFallback

Test plan

  • Verify that pages with sections whose loaders throw HttpError (429, 500) still return 200 and render the ErrorFallback for the affected section
  • Verify that direct invoke calls still propagate HttpError correctly (the isInvokeCtx check in wrapCaughtErrors is preserved)
  • Verify that pages with all sections healthy continue to work as before
  • Monitor Cloudflare healthchecks for affected sites after deploy

🤖 Generated with Claude Code


Summary by cubic

Contain HttpErrors thrown by section loaders so only the affected section shows its fallback instead of crashing the entire page. Pages now return 200; direct invoke calls still propagate HttpError as before.

  • Bug Fixes
    • Removed HttpError re-throws in blocks/loader.ts (wrapCaughtErrors), blocks/section.ts (section resolver .catch), and components/section.tsx (ErrorBoundary.getDerivedStateFromError) to route errors into the section boundary.
    • Failing sections render ErrorFallback; page status no longer mirrors upstream 429/500, preventing false healthcheck failures.

Written for commit 15cb1c0. Summary will update on new commits.

Summary by CodeRabbit

  • Refactor
    • Unified error handling: HTTP errors are now processed consistently through the standard error boundary mechanism rather than receiving exception-type-specific handling.
    • Simplified error propagation logic by consolidating error handling across loader, section blocks, and error boundary components into a uniform fallback mechanism.

… page

When a section's loader throws an HttpError (e.g., 429, 500 from upstream APIs),
the error was re-thrown at three levels — wrapCaughtErrors, section resolver catch,
and ErrorBoundary — causing the entire page to return the error status code instead
of containing the failure within the affected section.

This caused production incidents where a single ProductShelf section failing with
a 429 from VTEX would make the entire home page return 429, triggering Cloudflare
healthcheck failures (marked as Unhealthy/404).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 4, 2026

Tagging Options

Should a new tag be published when this PR is merged?

  • 👍 for Patch 1.190.1 update
  • 🎉 for Minor 1.191.0 update
  • 🚀 for Major 2.0.0 update

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 4, 2026

📝 Walkthrough

Walkthrough

The changes remove special-case error handling for HttpError instances across three files—a loader, section block, and section component—causing all errors to be uniformly processed through error boundaries and fallback mechanisms instead of being re-thrown.

Changes

Cohort / File(s) Summary
Unified Error Handling
blocks/loader.ts, blocks/section.ts, components/section.tsx
Removed HttpError imports and special-case instanceof HttpError checks. All errors now flow through standard error boundaries and fallback mechanisms instead of being re-thrown, unifying error propagation behavior across the error handling layer.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 Errors once special, now unified in grace,
No more exceptions thrown from place to place,
Through boundaries they flow, both far and near,
The error rabbit cheers—simplicity is here! 🎉

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main change: preventing HttpError from crashing the entire page by containing it within sections. It directly reflects the core problem and solution.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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 fix/contain-http-errors-in-sections

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.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 3 files

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
blocks/loader.ts (1)

97-138: ⚠️ Potential issue | 🔴 Critical

Verify client-side redirect handling in render.tsx still works.

The wrapCaughtErrors function wraps errors (including HttpError) in a proxy when not in invoke context. The isInvokeCtx check at line 103 correctly preserves HttpError propagation for direct invoke calls. However, render.tsx does not use invoke context.

When render.tsx calls state.deco.render(), the underlying state.resolve() has no isInvoke flag set. This means loaders that throw HttpError are wrapped by wrapCaughtErrors and returned as proxy values rather than thrown as exceptions. The try/catch block at runtime/features/render.tsx:94-102 never catches these wrapped errors since they are returned as values, not thrown. Consequently, the instanceof HttpError check at line 113 becomes unreachable, breaking client-side redirect handling.

This is a critical issue: HttpError-based redirects from loaders will silently fail to trigger error handling logic.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@blocks/loader.ts` around lines 97 - 138, wrapCaughtErrors currently converts
thrown HttpError into a proxy when not in an invoke context, causing render.tsx
(which calls state.deco.render() / state.resolve()) to receive a value instead
of an exception and thus miss HttpError-based redirects; update wrapCaughtErrors
(the catch block in wrapCaughtErrors) to detect HttpError (the HttpError
class/type used by your loaders) and rethrow it immediately instead of returning
a proxy so downstream callers like render.tsx can catch instanceof HttpError,
e.g. add an early if (err instanceof HttpError) throw err before
creating/returning the Proxy.
🧹 Nitpick comments (2)
components/section.tsx (1)

18-18: Potential formatting issue - verify with deno fmt.

Similar to blocks/section.ts, this blank line may have formatting issues. Run deno fmt to ensure consistency and avoid CI failures.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/section.tsx` at line 18, There’s a likely formatting/blank-line
inconsistency in components/section.tsx (mirrors blocks/section.ts) that can
fail CI; run deno fmt and fix any whitespace/blank-line differences so the file
matches project formatting conventions (remove the stray blank line or adjust
surrounding whitespace), then re-run the formatter to ensure
components/section.tsx is consistent with blocks/section.ts.
blocks/loader.ts (1)

9-9: Potential formatting issue - verify with deno fmt.

This blank line may have formatting issues similar to blocks/section.ts. Ensure consistent formatting across all changed files.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@blocks/loader.ts` at line 9, There’s a potential formatting/whitespace issue
in the loader.ts module: run deno fmt and remove any stray blank line or
trailing whitespace around the module header (the blank line near the top of the
loader.ts file) so the file matches the project's formatting rules; ensure the
file ends with a single newline and no extra blank lines.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@blocks/section.ts`:
- Line 22: Run the formatter (deno fmt) on the section module to fix the CI
failing style check; remove any trailing whitespace or incorrect blank line
around the exported Section symbol (or the module's default export) so
formatting matches the project's style, then commit the formatted file.

---

Outside diff comments:
In `@blocks/loader.ts`:
- Around line 97-138: wrapCaughtErrors currently converts thrown HttpError into
a proxy when not in an invoke context, causing render.tsx (which calls
state.deco.render() / state.resolve()) to receive a value instead of an
exception and thus miss HttpError-based redirects; update wrapCaughtErrors (the
catch block in wrapCaughtErrors) to detect HttpError (the HttpError class/type
used by your loaders) and rethrow it immediately instead of returning a proxy so
downstream callers like render.tsx can catch instanceof HttpError, e.g. add an
early if (err instanceof HttpError) throw err before creating/returning the
Proxy.

---

Nitpick comments:
In `@blocks/loader.ts`:
- Line 9: There’s a potential formatting/whitespace issue in the loader.ts
module: run deno fmt and remove any stray blank line or trailing whitespace
around the module header (the blank line near the top of the loader.ts file) so
the file matches the project's formatting rules; ensure the file ends with a
single newline and no extra blank lines.

In `@components/section.tsx`:
- Line 18: There’s a likely formatting/blank-line inconsistency in
components/section.tsx (mirrors blocks/section.ts) that can fail CI; run deno
fmt and fix any whitespace/blank-line differences so the file matches project
formatting conventions (remove the stray blank line or adjust surrounding
whitespace), then re-run the formatter to ensure components/section.tsx is
consistent with blocks/section.ts.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: c77a5093-9c29-4583-9eab-55ccc6a7e4d4

📥 Commits

Reviewing files that changed from the base of the PR and between b7cf6ef and 15cb1c0.

📒 Files selected for processing (3)
  • blocks/loader.ts
  • blocks/section.ts
  • components/section.tsx

} from "../engine/block.ts";
import type { Resolver } from "../engine/core/resolver.ts";
import { HttpError } from "../engine/errors.ts";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix formatting to pass CI.

The pipeline reports a deno fmt --check failure at this location. Run deno fmt to fix the formatting issue (likely a trailing whitespace or incorrect blank line).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@blocks/section.ts` at line 22, Run the formatter (deno fmt) on the section
module to fix the CI failing style check; remove any trailing whitespace or
incorrect blank line around the exported Section symbol (or the module's default
export) so formatting matches the project's style, then commit the formatted
file.

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