Skip to content

fix: move providers inside ErrorBoundary to prevent crash loop#4783

Open
frano-m wants to merge 2 commits intomainfrom
fran/4776-fix-filter-param-loop
Open

fix: move providers inside ErrorBoundary to prevent crash loop#4783
frano-m wants to merge 2 commits intomainfrom
fran/4776-fix-filter-param-loop

Conversation

@frano-m
Copy link
Copy Markdown
Contributor

@frano-m frano-m commented Apr 23, 2026

Summary

Fixes the infinite retry loop when a filter query parameter contains an invalid value (#4776).

Root Cause

ExploreStateProvider, DataDictionaryStateProvider, and FileManifestStateProvider were positioned above the ErrorBoundary in the component tree. When ExploreStateProvider's reducer crashed (e.g. JSON.parse on a malformed filter URL param, or accessing .length on a wrong-shape filter object), the error bypassed the ErrorBoundary entirely and bubbled up to Next.js's built-in error handling. Next.js attempted to recover by re-rendering the page, which hit the same crash again — creating an infinite loop.

Fix

Move the three providers inside the ErrorBoundary:

Before:                          After:
ExploreStateProvider             Main
  DataDictionaryStateProvider      ErrorBoundary ← catches all errors below
    Main                             ExploreStateProvider
      ErrorBoundary                    DataDictionaryStateProvider
        FileManifestStateProvider        FileManifestStateProvider
          Component                        Component

Now any error from the providers' reducers, hooks, or child components is caught by the ErrorBoundary and renders the Error fallback page. The Header and Footer remain outside the boundary so the user can still navigate away from the error page.

Why this works

The Error fallback component does not consume ExploreState, DataDictionaryState, or FileManifestState — it only needs the error object, a reset callback, and the root path (from app config). There is no reason these providers need to be above the boundary.

Closes #4776

Test plan

Tested all three invalid filter param cases:

  • Malformed/truncated JSON (?filter=%5B%7B%22categoryKey...) → shows error page
  • Wrong shape (?filter=[{"facetName":"bogus","terms":["invalid"]}]) → shows error page
  • Correct shape, invalid values (?filter=[{"categoryKey":"bogus","value":["invalid"]}]) → shows API 400 error page
  • Valid filters still work normally
  • Unit tests pass (101/101)
  • AnVIL Catalog e2e tests pass (48/48, 9 skipped)
  • AnVIL CMG e2e tests pass (125/126 — 1 pre-existing flaky filter tag failure)

🤖 Generated with Claude Code

image image

@frano-m frano-m requested a review from Copilot April 23, 2026 04:55
frano-m and others added 2 commits April 23, 2026 14:55
Move ExploreStateProvider, DataDictionaryStateProvider, and
FileManifestStateProvider inside the ErrorBoundary in _app.tsx.

Previously these providers sat above the ErrorBoundary. When a provider
crashed (e.g. ExploreStateProvider's reducer throwing on a malformed
filter URL param), the error bypassed the ErrorBoundary entirely and
bubbled up to Next.js's built-in error handling, which attempted to
recover by re-rendering the page — triggering the same crash in an
infinite loop.

With the providers inside the ErrorBoundary, any error from their
reducers, hooks, or child components is caught and rendered as the
Error fallback page. The header and footer remain visible (they are
intentionally outside the boundary) so the user can still navigate away.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@frano-m frano-m force-pushed the fran/4776-fix-filter-param-loop branch from 47ac5e7 to 571d693 Compare April 23, 2026 04:55
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Moves key state providers under the app-level ErrorBoundary so reducer/hook crashes (e.g., invalid filter URL params) are caught by the fallback UI instead of triggering Next.js re-render recovery loops.

Changes:

  • Reordered component tree in _app.tsx to place ExploreStateProvider, DataDictionaryStateProvider, and FileManifestStateProvider inside the ErrorBoundary.
  • Kept Header/Footer outside the boundary so navigation remains available on the error fallback page.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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.

Infinite retry loop on 404 when filter query param contains invalid value

3 participants