Skip to content

Add error scenarios hub and test pages#2497

Open
AbanoubGhadban wants to merge 14 commits into2402-streaming-hang-on-errorfrom
abanoub/2450-error-scenarios-hub
Open

Add error scenarios hub and test pages#2497
AbanoubGhadban wants to merge 14 commits into2402-streaming-hang-on-errorfrom
abanoub/2450-error-scenarios-hub

Conversation

@AbanoubGhadban
Copy link
Collaborator

@AbanoubGhadban AbanoubGhadban commented Feb 27, 2026

Summary

  • Adds a comprehensive error scenarios hub page (/error_scenarios_hub) with interactive config override controls for raise_on_prerender_error, throw_js_errors, and raise_non_shell_server_rendering_errors
  • Adds 10+ test pages covering all streaming/RSC/non-streaming error paths with detailed config-aware documentation
  • Config overrides auto-submit and forward to linked test pages so you can navigate between scenarios under the same conditions

Context

Split from #2486 (Fix silent error absorption in RSC payload injection) to separate the dummy app test/documentation pages from the core package/gem bug fixes.

Test plan

  • Visit /error_scenarios_hub and verify the 3 config dropdowns show current values
  • Change config values and verify the page re-renders with updated behavior descriptions
  • Click "Open page" links and verify the config overrides persist in the URL and take effect
  • Click "Reset to defaults" and verify all configs return to their default values

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added comprehensive error scenario testing hub with interactive configuration overrides and documentation for error behavior across rendering modes.
    • Added multiple test endpoints for validating error handling in server-side rendering and streaming scenarios.
  • Documentation

    • Included detailed reference tables and behavioral guides for error propagation across different rendering configurations.

AbanoubGhadban and others added 13 commits February 25, 2026 16:16
…2402)

Node.js stream.pipe() does not propagate errors from source to destination.
When a source stream errors, pipe() silently unpipes but leaves the
destination PassThrough open, causing any consumer awaiting stream.end
(like Fastify's res.send) to hang forever.

Fix at 5 locations across the streaming pipeline:
- handleStreamError: end PassThrough when source errors
- RSCRequestTracker: end tee'd streams when source errors
- injectRSCPayload: flush + end resultStream in all error paths
- pipeToTransform: end transformStream when piped stream errors
- consumer_stream_async: resolve first_chunk_var on exception

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Only end destination streams when the source is truly destroyed
(stream.destroyed === true), not on non-fatal errors. When
throwJsErrors is true, emitError() emits an error event without
destroying the stream — React continues rendering other suspense
boundaries. Ending the destination on any error caused "write after
end" as pipe() tried to forward subsequent data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Async component that always errors after 2s during streaming SSR.
Visit /stream_error_demo to reproduce:
- On master: browser hangs forever (loading spinner)
- On fix branch: response completes with error handled

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Throws immediately at the top level of the component, before React
can render any shell HTML. Visit /stream_shell_error_demo to reproduce.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…mination

'error' alone is not the end of a stream — non-fatal errors (e.g., emitError
for throwJsErrors) emit 'error' without destroying, and React may continue
rendering. The 'close' event fires after both normal 'end' and destroy(),
making it the reliable termination signal.

Changes:
- handleStreamError: split error handler (report only) from close handler (end PassThrough)
- RSCRequestTracker: use 'close' instead of 'error' to end tee'd streams
- injectRSCPayload: add 'close' listener on pipeableHtmlStream to end htmlStream
  when source is destroyed (closes gap where pipe unpipes silently), use 'close'
  on htmlStream for resultStream termination
- streamingUtils: use 'close' instead of 'error' + destroyed check
- Add test verifying non-fatal errors don't prematurely end the PassThrough

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move endResultStream after flush definition to fix ESLint no-use-before-define
- Remove redundant begin block in async do...end to fix RuboCop Style/RedundantBegin

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The 'close' handler on htmlStream was firing in the normal path (via
autoDestroy after 'end') and prematurely ending resultStream before RSC
data could be flushed. Node.js runs process.nextTick ('close' from
autoDestroy) before Promise microtasks (.then from the 'end' handler),
so endResultStream() always ran before rscPromise.then(cleanup).

Fix: check htmlStream.readableEnded in the 'close' handler — it's true
after normal 'end' (let the 'end' handler manage cleanup) and false
when destroyed without ending (the error case we actually want to
handle).

Also adds tests for RSC payloads arriving after the HTML stream
finishes, which were previously untested and would hang indefinitely
without this fix.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove issue references and reproduction language from test files.
Tests now describe the expected stream error handling behavior directly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix prettier formatting in test files
- Fix ESLint errors in demo components (unreachable code, line length)
- Remove issue references from demo component text
- Guard cleanup() against double-ending resultStream by delegating
  to endResultStream() which has writableEnded check
- Use bare `raise` instead of `raise e` to preserve original backtrace

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The `=> e` capture is unused after changing `raise e` to bare `raise`.

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

coderabbitai bot commented Feb 27, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This pull request adds comprehensive error scenario testing infrastructure to the React on Rails Pro dummy application, including a new error scenarios hub view with configuration overrides, multiple test action endpoints for SSR and streaming error scenarios, new React test components for deterministic error demonstrations, and corresponding routes and UI navigation elements.

Changes

Cohort / File(s) Summary
Controller and Route Configuration
react_on_rails_pro/spec/dummy/app/controllers/pages_controller.rb, react_on_rails_pro/spec/dummy/config/routes.rb
Added 13 new controller actions for error/scenario testing (error_scenarios_hub, reset_error_configs, ssr_shell_error, ssr_async_error, ssr_sync_error, ssr_async_prop_error, rsc_component_error, stream_error_demo, stream_shell_error_demo, non_existing_*) plus apply_config_overrides private method to override ReactOnRails configuration flags. Corresponding GET/POST routes added with named route helpers.
Error Scenarios Hub
react_on_rails_pro/spec/dummy/app/views/pages/error_scenarios_hub.html.erb
Comprehensive interactive testing hub view displaying runtime configuration values, override UI form with selects, current configuration dashboard, and extensive documentation of error behaviors across non-streaming, streaming, and RSC rendering paths with observational tables and data-flow diagrams.
SSR Error Testing Views
react_on_rails_pro/spec/dummy/app/views/pages/ssr_*.html.erb
Four views for testing SSR error scenarios: ssr_shell_error, ssr_async_error, ssr_sync_error, ssr_async_prop_error, each using stream_react_component with specific component names and error-triggering props.
Streaming Error Testing Views
react_on_rails_pro/spec/dummy/app/views/pages/stream_*.html.erb
Two views for streaming error demonstrations: stream_error_demo and stream_shell_error_demo, each rendering React components via stream_react_component with tracing enabled.
RSC and Non-existent Component Views
react_on_rails_pro/spec/dummy/app/views/pages/rsc_component_error.html.erb, react_on_rails_pro/spec/dummy/app/views/pages/non_existing_*.html.erb
Three views testing RSC and non-existent component scenarios: rsc_component_error using stream_react_component, plus non_existing_react_component, non_existing_stream_react_component, and non_existing_rsc_payload for handling missing component errors.
Navigation UI
react_on_rails_pro/spec/dummy/app/views/shared/_menu.erb
Added menu item "Error Scenario Tests" linking to error_scenarios_hub_path with active-state styling.
React Test Components
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/DeterministicRSCErrorComponent.tsx, react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/StreamErrorDemo.jsx, react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/StreamShellErrorDemo.jsx, react_on_rails_pro/spec/dummy/client/app/ServerComponentRouter.tsx
Three new error test fixture components: DeterministicRSCErrorComponent (deterministically throws error), StreamErrorDemo (simulates async rejection in Suspense boundary), StreamShellErrorDemo (throws during shell rendering). Updated ServerComponentRouter with "Deterministic RSC Error" link and route.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A rabbit builds error paths with care,
SSR streams and RSC layers fair,
Testing every edge case that could break,
Now the hub guides each testing state,
Hop through configs—no more heartache! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add error scenarios hub and test pages' directly and clearly summarizes the main change: introducing an error scenarios hub and associated test pages for demonstrating various error handling scenarios.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch abanoub/2450-error-scenarios-hub

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.

@claude
Copy link

claude bot commented Feb 27, 2026

Review: PR #2497 — Add error scenarios hub and test pages

Overall this is a well-documented and useful addition for manual testing of error paths. The hub page is genuinely informative with its config explanations and history. A few issues worth addressing before merge:


Critical: apply_config_overrides runs on ALL controller actions

The before_action :apply_config_overrides is placed at the top of PagesController with no only: or except: guard, meaning any request to any page (hello world, shared store, server router, etc.) can mutate the global ReactOnRails.configuration and ReactOnRailsPro.configuration singletons by appending query params. This is likely unintentional.

Suggested fix — scope it to error-related actions only:

before_action :apply_config_overrides, only: %i[
  error_scenarios_hub
  ssr_shell_error ssr_async_error ssr_sync_error ssr_async_prop_error
  rsc_component_error non_existing_react_component
  non_existing_stream_react_component non_existing_rsc_payload
  stream_error_demo stream_shell_error_demo
]

Critical: Global config mutation is not thread-safe

apply_config_overrides writes to global ReactOnRails.configuration and ReactOnRailsPro.configuration singletons, which are shared across all threads in a multi-threaded Puma server. If two test requests execute concurrently (e.g., in parallel test suites), one request's config change can affect the other's rendering — causing flaky test results that are hard to diagnose.

Consider adding a comment at minimum, or using a request-scoped config approach (e.g., thread-local storage or per-request options if supported).


Bug: reset_error_configs uses wrong default for throw_js_errors

The hub page's own documentation says the default for throw_js_errors is true (changed in Jun 2023, Pro PR #328), but reset_error_configs resets it to false:

ReactOnRailsPro.configuration.throw_js_errors = false  # should be true per documented default

This means 'Reset to defaults' doesn't actually restore the real defaults.


Minor: Non-standard async component pattern in StreamErrorDemo

AlwaysFailsAsync is a regular (non-async) function that returns a Promise on the server side:

const AlwaysFailsAsync = () => {
  if (typeof window !== 'undefined') {
    return <div>Client-side fallback</div>;
  }
  return new Promise((_resolve, reject) => { ... });
};

React 19 async server components are expected to be declared with async function. A non-async function returning a raw Promise is technically undefined behavior in React's reconciler. Using async function AlwaysFailsAsync() would be more correct and less likely to break across React versions.


Minor: Config mutations via GET request

apply_config_overrides mutates global state on GET requests (via URL query params and the onchange auto-submit). This bypasses CSRF protection since the form uses method: :get. Since this is a dev/test-only dummy app this is acceptable, but worth a comment explaining the choice is intentional.


Nit: 1041-line ERB file

error_scenarios_hub.html.erb is 1041 lines. Consider extracting each config card into a partial for easier navigation and future maintenance.

session[:something_useful] = "REALLY USEFUL"
end

before_action :apply_config_overrides
Copy link

Choose a reason for hiding this comment

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

The apply_config_overrides before_action has no only: or except: scope, so it runs on every controller action. Any page in this app (hello world, server router, shared store, etc.) can have its global configuration mutated by a visitor who appends ?raise_on_prerender_error=false to any URL.

Suggested change
before_action :apply_config_overrides
before_action :apply_config_overrides, only: %i[
error_scenarios_hub
ssr_shell_error ssr_async_error ssr_sync_error ssr_async_prop_error
rsc_component_error non_existing_react_component
non_existing_stream_react_component non_existing_rsc_payload
stream_error_demo stream_shell_error_demo
]

def reset_error_configs
ReactOnRails.configuration.raise_on_prerender_error = Rails.env.development?
ReactOnRailsPro.configuration.throw_js_errors = false
ReactOnRailsPro.configuration.raise_non_shell_server_rendering_errors = false
Copy link

Choose a reason for hiding this comment

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

This resets throw_js_errors to false, but the hub page's own documentation states the default is true (changed in Jun 2023, Pro PR #328). "Reset to defaults" will leave users in a non-default state.

Suggested change
ReactOnRailsPro.configuration.raise_non_shell_server_rendering_errors = false
ReactOnRailsPro.configuration.throw_js_errors = true

ReactOnRails.configuration.raise_on_prerender_error =
bool.cast(params[:raise_on_prerender_error])
end
if params[:throw_js_errors].present?
Copy link

Choose a reason for hiding this comment

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

Thread-safety concern: This method mutates global configuration singletons (ReactOnRails.configuration, ReactOnRailsPro.configuration) which are shared across all threads in a multi-threaded Puma server. If two requests are processed concurrently — which can happen in parallel test suites — one request's config override can bleed into another's render, producing flaky, hard-to-diagnose failures.

Consider adding a comment here to document this limitation, e.g.:

# NOTE: This mutates global config singletons and is NOT thread-safe.
# Intended only for single-threaded manual testing in the dummy app.
# Running tests with concurrency enabled may cause flaky results.

if (typeof window !== 'undefined') {
return <div>Client-side fallback</div>;
}
return new Promise((_resolve, reject) => {
Copy link

Choose a reason for hiding this comment

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

A regular (non-async) function returning a Promise on the server side is not the standard pattern for async React components in React 19. React's reconciler expects async server components to be declared as async function. A non-async function returning a raw Promise may behave inconsistently across React versions.

Consider:

const AlwaysFailsAsync = async () => {
  if (typeof window !== 'undefined') {
    return <div>Client-side fallback</div>;
  }
  await new Promise((_resolve, reject) => {
    setTimeout(() => reject(new Error('Async component crashed during server rendering!')), 2000);
  });
};

Copy link
Contributor

@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.

🧹 Nitpick comments (2)
react_on_rails_pro/spec/dummy/app/views/pages/error_scenarios_hub.html.erb (1)

56-60: Minor text inconsistency with auto-submit behavior.

The instruction says "Change values and click Apply" but the form auto-submits on change (via onchange="this.form.submit()"). The Apply button only appears in the <noscript> fallback. Consider updating the text to reflect the auto-submit behavior.

📝 Suggested text update
   <p style="margin-top: 0; font-size: 0.9em;">
-    Change values and click <strong>Apply</strong> to mutate the global config singletons.
+    Change values to automatically apply and mutate the global config singletons.
     Linked "Open page" test pages will use the overridden values.
   </p>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@react_on_rails_pro/spec/dummy/app/views/pages/error_scenarios_hub.html.erb`
around lines 56 - 60, Update the explanatory text to reflect the form's
auto-submit behavior: replace "Change values and click Apply to mutate the
global config singletons." with wording that mentions changes are submitted
automatically on change (because of onchange="this.form.submit()") and that the
Apply button only appears as a <noscript> fallback for users without JavaScript;
adjust the copy around the "Open page" reference if needed so it clearly
communicates that overridden values are applied immediately in JS-enabled
browsers and the Apply button is only for non-JS fallback.
react_on_rails_pro/spec/dummy/app/controllers/pages_controller.rb (1)

22-22: Consider scoping apply_config_overrides to error scenario actions only.

The before_action applies to all controller actions, meaning every request will check params and potentially modify global configuration. While this is likely intentional to allow config overrides to persist when navigating from the hub to test pages, you might consider limiting it to relevant actions using only: to avoid unintended config changes on unrelated pages.

If the current behavior is intentional (to allow any page to accept config override params), this is fine for a test app.

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

In `@react_on_rails_pro/spec/dummy/app/controllers/pages_controller.rb` at line
22, PagesController currently runs before_action :apply_config_overrides for
every action which can unintentionally mutate global config; restrict this to
only the actions that render the hub/test pages by changing the before_action to
scope apply_config_overrides (use the only: option) and list the relevant action
names that accept override params (e.g., the hub and test page actions handled
by PagesController such as the actions that render test pages or show pages);
update the before_action line referencing apply_config_overrides in
PagesController accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@react_on_rails_pro/spec/dummy/app/controllers/pages_controller.rb`:
- Line 22: PagesController currently runs before_action :apply_config_overrides
for every action which can unintentionally mutate global config; restrict this
to only the actions that render the hub/test pages by changing the before_action
to scope apply_config_overrides (use the only: option) and list the relevant
action names that accept override params (e.g., the hub and test page actions
handled by PagesController such as the actions that render test pages or show
pages); update the before_action line referencing apply_config_overrides in
PagesController accordingly.

In `@react_on_rails_pro/spec/dummy/app/views/pages/error_scenarios_hub.html.erb`:
- Around line 56-60: Update the explanatory text to reflect the form's
auto-submit behavior: replace "Change values and click Apply to mutate the
global config singletons." with wording that mentions changes are submitted
automatically on change (because of onchange="this.form.submit()") and that the
Apply button only appears as a <noscript> fallback for users without JavaScript;
adjust the copy around the "Open page" reference if needed so it clearly
communicates that overridden values are applied immediately in JS-enabled
browsers and the Apply button is only for non-JS fallback.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 11034a5 and fdda266.

📒 Files selected for processing (18)
  • react_on_rails_pro/spec/dummy/app/controllers/pages_controller.rb
  • react_on_rails_pro/spec/dummy/app/views/pages/error_scenarios_hub.html.erb
  • react_on_rails_pro/spec/dummy/app/views/pages/non_existing_react_component.html.erb
  • react_on_rails_pro/spec/dummy/app/views/pages/non_existing_rsc_payload.html.erb
  • react_on_rails_pro/spec/dummy/app/views/pages/non_existing_stream_react_component.html.erb
  • react_on_rails_pro/spec/dummy/app/views/pages/rsc_component_error.html.erb
  • react_on_rails_pro/spec/dummy/app/views/pages/ssr_async_error.html.erb
  • react_on_rails_pro/spec/dummy/app/views/pages/ssr_async_prop_error.html.erb
  • react_on_rails_pro/spec/dummy/app/views/pages/ssr_shell_error.html.erb
  • react_on_rails_pro/spec/dummy/app/views/pages/ssr_sync_error.html.erb
  • react_on_rails_pro/spec/dummy/app/views/pages/stream_error_demo.html.erb
  • react_on_rails_pro/spec/dummy/app/views/pages/stream_shell_error_demo.html.erb
  • react_on_rails_pro/spec/dummy/app/views/shared/_menu.erb
  • react_on_rails_pro/spec/dummy/client/app/components/ServerComponentRouter.tsx
  • react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/DeterministicRSCErrorComponent.tsx
  • react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/StreamErrorDemo.jsx
  • react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/StreamShellErrorDemo.jsx
  • react_on_rails_pro/spec/dummy/config/routes.rb

@greptile-apps
Copy link

greptile-apps bot commented Feb 27, 2026

Greptile Summary

This PR adds comprehensive error testing infrastructure to the dummy app:

  • /error_scenarios_hub page with interactive config override controls for raise_on_prerender_error, throw_js_errors, and raise_non_shell_server_rendering_errors
  • 10+ test pages covering streaming/RSC/non-streaming error paths (shell errors, async errors, sync errors, missing components, etc.)
  • Config overrides persist across navigation via query params
  • New React test components: StreamErrorDemo, StreamShellErrorDemo, DeterministicRSCErrorComponent

Issue found:

  • StreamErrorDemo.jsx returns a Promise instead of throwing it, which won't trigger React Suspense error handling correctly

Confidence Score: 3/5

  • Safe to merge after fixing the logic bug in StreamErrorDemo.jsx
  • Score reflects one critical logic bug in StreamErrorDemo.jsx (returning Promise instead of throwing it) that will prevent the error demo from working correctly. The rest of the changes are well-structured test pages with proper route/controller setup. Global config mutation is acceptable for a test dummy app.
  • Pay close attention to react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/StreamErrorDemo.jsx - contains a logic bug

Important Files Changed

Filename Overview
react_on_rails_pro/spec/dummy/app/controllers/pages_controller.rb Adds config override before_action and 10+ error scenario controller actions; global config mutation acceptable for test app
react_on_rails_pro/spec/dummy/app/views/pages/error_scenarios_hub.html.erb Comprehensive error scenarios hub with config controls and detailed documentation; well-structured test page
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/StreamErrorDemo.jsx Returns Promise instead of throwing it in AlwaysFailsAsync; should use throw for proper Suspense handling
react_on_rails_pro/spec/dummy/config/routes.rb Adds 11 new routes for error scenario pages; routes correctly defined with appropriate HTTP methods

Last reviewed commit: fdda266

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

18 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +9 to +11
return new Promise((_resolve, reject) => {
setTimeout(() => reject(new Error('Async component crashed during server rendering!')), 2000);
});
Copy link

Choose a reason for hiding this comment

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

Returning a Promise isn't valid React - components must return JSX or primitives. To trigger Suspense error handling, throw the Promise instead:

Suggested change
return new Promise((_resolve, reject) => {
setTimeout(() => reject(new Error('Async component crashed during server rendering!')), 2000);
});
throw new Promise((_resolve, reject) => {
setTimeout(() => reject(new Error('Async component crashed during server rendering!')), 2000);
});

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fdda266fbc

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

<span class="<%= throw_js_errors ? 'config-val-true' : 'config-val-false' %>"><%= throw_js_errors %></span>
</h4>
<p><strong>Gem:</strong> <code>react_on_rails_pro</code> &nbsp;|&nbsp;
<strong>Default:</strong> <code>true</code> &nbsp;|&nbsp;

Choose a reason for hiding this comment

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

P2 Badge Correct throw_js_errors default shown on error hub

The hub hard-codes throw_js_errors as Default: true, but this dummy app config initializes that setting to false (spec/dummy/config/initializers/react_on_rails_pro.rb) and reset_error_configs also resets it to false, so clicking “Reset to defaults” leaves the page contradicting its own default documentation. This makes the scenario matrix misleading and can send debugging toward the wrong expected behavior.

Useful? React with 👍 / 👎.

@AbanoubGhadban AbanoubGhadban changed the base branch from master to 2402-streaming-hang-on-error February 27, 2026 15:46
Add a comprehensive error scenarios hub page with:
- Interactive config override controls for raise_on_prerender_error,
  throw_js_errors, and raise_non_shell_server_rendering_errors
- Auto-submit dropdowns with config param forwarding to linked pages
- Detailed documentation of 10 error scenarios (A-I + N) with
  config-aware behavior descriptions
- Summary table showing expected behavior under each config combination

Add test pages for each error scenario:
- SSR shell error, async error, sync error, async prop error
- RSC component error (via server router)
- Stream error demo and stream shell error demo
- Non-existing component pages (non-streaming, streaming, RSC)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@AbanoubGhadban AbanoubGhadban force-pushed the abanoub/2450-error-scenarios-hub branch from fdda266 to c09d44a Compare February 27, 2026 15:47
session[:something_useful] = "REALLY USEFUL"
end

before_action :apply_config_overrides
Copy link

Choose a reason for hiding this comment

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

Consider scoping this before_action to error scenario actions only.

apply_config_overrides mutates global ReactOnRails.configuration and ReactOnRailsPro.configuration singletons. With no only: guard, every request to every page in the dummy app (hello-world, shared store, server router, etc.) will check URL params and potentially overwrite these globals.

This means a leftover ?throw_js_errors=true param in a copy-pasted URL could silently affect unrelated test pages without the developer realising why.

Suggested change
before_action :apply_config_overrides
before_action :apply_config_overrides, only: %i[
error_scenarios_hub reset_error_configs
ssr_shell_error ssr_async_error ssr_sync_error ssr_async_prop_error
rsc_component_error non_existing_react_component
non_existing_stream_react_component non_existing_rsc_payload
stream_error_demo stream_shell_error_demo
]

<div style="padding: 1em; border: 2px solid #4caf50; border-radius: 6px; background: #e8f5e9; margin-bottom: 1.5em;">
<h3 style="margin-top: 0;">Override Configs (runtime)</h3>
<p style="margin-top: 0; font-size: 0.9em;">
Change values and click <strong>Apply</strong> to mutate the global config singletons.
Copy link

Choose a reason for hiding this comment

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

The text says "click Apply" but the form auto-submits via onchange="this.form.submit()" — the Apply button only appears inside <noscript> for non-JS fallback. The instruction is misleading for JS-enabled browsers.

Suggested change
Change values and click <strong>Apply</strong> to mutate the global config singletons.
Change values to automatically apply and mutate the global config singletons.

@AbanoubGhadban AbanoubGhadban force-pushed the 2402-streaming-hang-on-error branch from b6204e6 to 2185635 Compare February 27, 2026 16:59
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.

2 participants