Skip to content

Conversation

@AbanoubGhadban
Copy link
Collaborator

@AbanoubGhadban AbanoubGhadban commented Oct 30, 2025

Summary

Cause of the error

The error happens because of the following bug:

  • If a streaming page started streaming and sent some html chunks to rails side.
  • In the middle of the streaming process, a connection error happens like ConnectionTimeout or a descriptor closed error.
  • The retries plugin at HTTPx retries to make the request again.
  • When the retry happens, some of the HTML chunks are already processed and sent or are on the way to the client.
  • When the request is made again, the returned chunks are appended to the original HTML chunks returned from the first erroneous request.
  • The sent HTML to the client contains erroneous and non-errornous HTML, which causes DOM errors and hydration errrors.
  • The same problem happens if the retry logic written by us at the request.rb file is executed instead of the HTTPx retry logic.

The exact scenario happens at the failing test

To check the error that happens and cause HTTPx retry plugin to retry the request, I wrote the following code at the code that initiates the HTTPx object

HTTPX
# For persistent connections we want retries,
# so the requests don't just fail if the other side closes the connection
# https://honeyryderchuck.gitlab.io/httpx/wiki/Persistent
.plugin(
  :retries,
  max_retries: 1,
  retry_change_requests: true,
  retry_after: ->(req, res) do
    Rails.logger.error("An error occured and retry is going to be made")
    Rails.logger.error("Error: #{res.error}")
    Rails.logger.error("Request Body: #{req.body&.to_s.first(1000)}")
    nil
  end,
)

It logs the error that happens and causes the retry to happen. And by checking the testing log file here. I found that the error happens is

Error: descriptor closed

Which happens for no specific reason, I already increased all timeout values at HTTPx side by setting the following configs

timeout: {
  connect_timeout: 100,
  read_timeout: 100,
  write_timeout: 100,
  request_timeout: 100,
  operation_timeout: 100,
  keep_alive_timeout: 100,
}

And at Fastify side, I added the following:

const app = fastify({
  http2: useHttp2 as true,
  bodyLimit: 104857600, // 100 MB
  logger:
    logHttpLevel !== 'silent' ? { name: 'RORP HTTP', level: logHttpLevel, ...sharedLoggerOptions } : false,
  ...fastifyServerOptions,
  pluginTimeout: 1_000_1000,
  requestTimeout: 1_000_1000,
  keepAliveTimeout: 1_000_1000,
  connectionTimeout: 1_000_1000,
  http2SessionTimeout: 1_000_1000,
});

And the same error still happens. It's planned to reproduce the error outside React on Rails and check if it's a problem at HTTPx or at Fastify and report the issue then. However, when the HTTPx retries plugin is removed, the error disappears, which makes us suspect that the problem is at HTTPx.

Reproduce the problem locally

To reproduce the problem locally, try opening a streaming page that takes too long to render and causes a Timeout error. You can try to open http://localhost:3000/rsc_posts_page_over_redis?artificial_delay=3000 page, and you can see that the page content is repeated twice before redirecting you to the 500 error page. At the CI test, the page is not redirected to the 500 error page, because at the second trial to SSR the page, no Timeout error happens.
You can try to reproduce it locally by adding a code like this to the RSCPageComponent

const newProps = { ...props };
if (fs.existsSync('./skip_js_delay')) {
  newProps.artificialDelay = 0;
  fs.rmSync('./skip_js_delay');
} else {
  fs.writeFileSync('./skip_js_delay', '');
}

This change is Reviewable

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 30, 2025

Walkthrough

The HTTPX retries plugin configuration in the request module was enhanced to use a block form that adds a retry_after handler. This handler logs error messages and truncated request bodies, then returns nil to trigger retries. No behavioral changes to retry mechanisms or timeouts; existing options remain unchanged.

Changes

Cohort / File(s) Summary
HTTPX Retries Plugin Enhancement
react_on_rails_pro/lib/react_on_rails_pro/request.rb
Enhanced retries plugin configuration by converting to block form with retry_after handler that logs errors and request body details before triggering retries

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Single file modification with focused scope
  • Configuration enhancement to existing plugin
  • Verify logging logic doesn't introduce performance concerns
  • Confirm truncation strategy for request body handling is appropriate

Suggested reviewers

  • alexeyr-ci2

Poem

🐰 A retry block hops through the code,
Logging errors down the road,
With truncated bodies in sight,
Our HTTPX flows just right!

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The PR title "Fix failing rspec test for non hydrated streamed page" indicates that the changeset involves fixing or updating an rspec test. However, the raw summary shows that the actual changes are in production code within react_on_rails_pro/lib/react_on_rails_pro/request.rb, specifically in the create_connection method where the HTTPX retries plugin configuration was enhanced with a retry_after handler. The title is misleading because it suggests the PR fixes the test itself, when the actual change is in the underlying request handling logic that fixes the issue causing the test to fail. While the title relates to the overall objective (resolving a failing test), it mischaracterizes the nature of the change, which would lead a developer scanning the history to expect test modifications rather than production code enhancements. Consider revising the title to accurately reflect the production code changes, such as "Enhance HTTPX retries plugin to handle request body errors" or "Fix EOFError in request handling for streamed pages". This would better communicate to reviewers and future developers that the fix involves improving retry handling logic rather than modifying test code.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-failing-rspec-test-for-non-hydrated-streamed-page

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.

@coderabbitai coderabbitai bot added the bug label Oct 30, 2025
@claude
Copy link

claude bot commented Oct 30, 2025

Code Review - PR #1892: Fix failing rspec test for non hydrated streamed page

Summary

This PR removes a console.error statement from the reportError function in ReactOnRailsRSC.ts. The change prevents an error message from being logged during RSC generation error handling.


✅ Positive Aspects

  1. Clean, focused change: Single line deletion with clear intent
  2. Preserves error handling logic: The actual error handling mechanism (emitting errors when throwJsErrors is true and tracking error state) remains intact
  3. No test changes required: Suggests this was extraneous logging

🔍 Issues & Concerns

1. Missing PR Description (Critical)

The PR body still contains placeholder text and hasn't been filled out. Please provide:

  • What bug was this fixing? What test was failing and why?
  • Root cause: Why was the console.error causing the test to fail?
  • Expected behavior: Why should this error NOT be logged?

2. Incomplete Checklist (Critical)

All checklist items are unchecked:

  • Add/update test to cover these changes
  • Update documentation
  • Update CHANGELOG file

Required actions:

  • Add regression test or explain why the existing test coverage is sufficient
  • Update CHANGELOG.md with an entry at the top explaining this fix
  • Document why this console.error was problematic

3. Inconsistent Error Logging (Medium)

There's another similar console.error at transformRSCStreamAndReplayConsoleLogs.ts:82:

console.error('Error transforming RSC stream:', error);

Questions:

  • Should this one also be removed for consistency?
  • What's the principle for when RSC errors should/shouldn't be logged?
  • Consider documenting the error logging strategy

4. Missing Context in Commit Messages (Low)

The commit message "remove error log during rsc generation error handling" could be more descriptive:

  • What test was failing?
  • Why does the console.error cause the failure?

🧪 Testing Concerns

  1. What test was failing? The PR title mentions "non hydrated streamed page" but I couldn't locate a corresponding test
  2. How can we verify the fix? Need steps to reproduce the original failure
  3. Could this hide legitimate errors? Removing error logging could make debugging harder

📋 Action Items

Before merging:

  1. Fill out the PR description with clear bug description and root cause
  2. Update CHANGELOG.md with an entry explaining this fix
  3. Add or reference test coverage that validates this behavior
  4. Document the decision: Add a code comment explaining why this error should NOT be logged, e.g.:
    const reportError = (error: Error) => {
      // Note: We intentionally don't console.error here because [reason]
      // Errors are handled via emitError() when throwJsErrors is enabled
      if (throwJsErrors) {
        emitError(error);
      }
  5. Consider consistency: Review all RSC error logging and establish a clear pattern

💡 Recommendations

  1. Add a test that verifies console output doesn't contain unexpected error messages during streaming
  2. Document error handling strategy for RSC in comments or docs
  3. Review similar code paths for consistency in error logging approach

⚖️ Overall Assessment

Conditionally approve pending required changes

The code change itself is reasonable and targeted, but the PR lacks essential context and documentation. The removal of console.error suggests it was interfering with test expectations around console output, but without explicit documentation, future maintainers won't understand why this error isn't logged.

Recommendation: Request changes to complete the PR checklist and add proper documentation before merging.

@claude
Copy link

claude bot commented Oct 31, 2025

Code Review: Fix failing rspec test for non hydrated streamed page

Summary

This PR removes a console.error statement from the reportError function in the RSC streaming code. The change aims to reduce console noise while maintaining proper error state tracking.


Positive Aspects

Error state tracking preserved: The change correctly maintains the error handling logic - renderState.hasErrors and renderState.error are still set appropriately

Conditional error emission intact: The throwJsErrors flag still controls whether errors are emitted to the stream via emitError()

Minimal, focused change: Single-line removal reduces risk


Issues & Concerns

1. Inconsistency with Similar Code ⚠️

Looking at streamServerRenderedReactComponent.ts:48-55, the regular React streaming has a reportError function that does NOT include a console.error call. However, there's an important difference:

  • Regular React streaming (streamServerRenderedReactComponent.ts): Uses onError callback which may already log errors internally via React
  • RSC streaming (ReactOnRailsRSC.ts): Uses custom error handling that may not have built-in logging

Question: Was the console.error serving a purpose in development/debugging that will now be lost? Consider whether errors will still be visible when throwJsErrors: false.

2. Missing PR Documentation

The PR description uses the template placeholder text and doesn't explain:

  • What test was failing and why
  • Why the console.error was causing the test to fail
  • Whether this impacts error visibility in production/development
  • Any alternative logging mechanism in place

Action Required: Please update the PR description with:

  • The specific test that was failing
  • Root cause analysis (why did console.error cause a test failure?)
  • Impact assessment (will developers still see RSC errors?)

3. Test Coverage Gaps ⚠️

The PR checklist shows:

  • Add/update test to cover these changes
  • Update CHANGELOG file

Concerns:

  • No test changes in this PR - how can we verify the fix works?
  • How do we prevent regression if the console.error was removed to fix a specific test scenario?

Recommendation: Add a test that verifies:

  1. Errors during RSC streaming are properly tracked in renderState
  2. Console output matches expected behavior
  3. The specific non-hydrated streaming scenario that was failing

4. Potential Silent Failures 🔴

With throwJsErrors: false, errors will now only be stored in renderState without any console output. This could make debugging significantly harder:

const reportError = (error: Error) => {
  // No logging when throwJsErrors is false!
  if (throwJsErrors) {
    emitError(error);
  }
  renderState.hasErrors = true;
  renderState.error = error;
};

Suggestion: Consider conditional logging:

const reportError = (error: Error) => {
  if (throwJsErrors) {
    emitError(error);
  } else if (process.env.NODE_ENV === 'development') {
    console.error('Error in RSC stream', error);
  }
  renderState.hasErrors = true;
  renderState.error = error;
};

Questions for Author

  1. What specific test was failing with the console.error present?
  2. Was the test checking console output and expecting it to be clean?
  3. Are there other mechanisms in place that will log RSC streaming errors?
  4. Have you verified error visibility in both development and production modes?
  5. Does the error still get logged somewhere else in the stack (e.g., via the transformRenderStreamChunksToResultObject or handleError functions)?

Recommendations

  1. Update PR description with context about the failing test
  2. Add test coverage for the specific scenario being fixed
  3. Consider environment-aware logging to preserve development error visibility
  4. Update CHANGELOG as noted in the checklist
  5. Verify error visibility - ensure errors are still discoverable when throwJsErrors: false

Code Quality Notes

  • No linting issues expected (removal of code)
  • No security concerns
  • No performance impact
  • TypeScript types remain valid

Conclusion

While the change is technically correct and maintains error state tracking, the lack of context and test coverage is concerning. The removal of logging could make debugging harder in scenarios where throwJsErrors: false.

Recommendation: Request additional context before merging, and consider adding environment-aware logging to preserve error visibility during development.


Status: ⚠️ Changes Requested - Need PR description update, test coverage, and error visibility verification

@claude
Copy link

claude bot commented Nov 1, 2025

Code Review - PR #1892: Fix failing rspec test for non hydrated streamed page

Summary

This PR removes a console.error statement from the RSC stream error handling path. The change reduces console noise during test execution while maintaining proper error state tracking.


Code Quality & Best Practices ✅

Positive aspects:

  • The change is minimal and focused on the specific issue
  • Error state is still properly tracked via renderState.hasErrors = true and renderState.error = error
  • Conditional error reporting logic remains intact (throwJsErrors flag is still respected)

Concerns:

  1. Observability Trade-off: Removing the console.error reduces visibility into RSC stream errors during development and debugging. This could make troubleshooting more difficult in production environments.

  2. Inconsistent Error Handling: The error is only logged when throwJsErrors is true (via emitError), but not logged when throwJsErrors is false. This creates a silent failure mode where errors are tracked in state but not visible to developers.

  3. Test-Driven Code Changes: The change appears to be fixing a test issue rather than fixing the underlying problem. Consider whether the test expectations should be adjusted instead.


Recommendations

  1. Consider conditional logging instead of removal:

    const reportError = (error: Error) => {
      if (throwJsErrors) {
        console.error('Error in RSC stream', error);
        emitError(error);
      }
      renderState.hasErrors = true;
      renderState.error = error;
    };

    This maintains visibility when errors should be thrown while keeping tests clean.

  2. Alternative: Use a debug flag:

    const reportError = (error: Error) => {
      if (process.env.NODE_ENV === 'development') {
        console.error('Error in RSC stream', error);
      }
      if (throwJsErrors) {
        emitError(error);
      }
      renderState.hasErrors = true;
      renderState.error = error;
    };
  3. Document the change: Add a code comment explaining why the console.error was removed and when errors will still be visible.


Test Coverage ⚠️

Issues:

  • The PR description's checklist is incomplete (all items unchecked)
  • No test updates mentioned
  • No CHANGELOG entry added

Required actions per CLAUDE.md:

  • Add/update test to cover these changes
  • Update CHANGELOG file (add entry at the top)
  • Provide a meaningful PR description explaining the bug and why this fix is appropriate

Performance Considerations ✅

No performance impact - the change removes a synchronous operation.


Security Concerns ✅

No security implications identified.


Additional Notes

The related test at integration_spec.rb:416-422 verifies that non-hydrated streamed pages work correctly without JavaScript. The console.error was likely appearing in test output even though it wasn't an actual error for that test scenario.

Suggested next steps:

  1. Complete the PR checklist
  2. Add a more descriptive PR summary explaining what test was failing and why
  3. Consider one of the conditional logging approaches above
  4. Update CHANGELOG with this bug fix
  5. Ensure bundle exec rubocop passes before merging

Reference

  • File: packages/react-on-rails-pro/src/ReactOnRailsRSC.ts:57-64
  • Test: react_on_rails_pro/spec/dummy/spec/system/integration_spec.rb:416-422

@claude
Copy link

claude bot commented Nov 1, 2025

Code Review: Fix failing rspec test for non hydrated streamed page

Summary

This PR removes a console.error() call from the reportError function in ReactOnRailsRSC.ts:58. The change appears to reduce console noise during error handling while maintaining proper error state tracking.

Analysis

What the code does:

The reportError function in the RSC streaming module handles errors that occur during server-side rendering:

  • Sets error state flags (renderState.hasErrors = true, renderState.error = error)
  • Conditionally emits errors via emitError(error) when throwJsErrors is enabled
  • Previously logged all errors to console regardless of throwJsErrors setting

Code Quality: ✅ Good

Positive aspects:

  1. Consistency improvement: The regular SSR streaming code in streamServerRenderedReactComponent.ts:48-55 has a similar reportError function that does NOT log to console, making this change bring RSC error handling in line with standard SSR behavior
  2. Clean separation of concerns: Error state management is separate from error reporting, and the throwJsErrors flag properly controls whether errors should be emitted
  3. Preserves functionality: Error state is still properly tracked via renderState.hasErrors and renderState.error

Potential concerns:

  1. Observability tradeoff: Removing the console.error reduces visibility into RSC stream errors during development/debugging
  2. Silent failures: When throwJsErrors: false, errors may now fail silently without any logging

Recommendations

1. Consider conditional logging (Optional Enhancement)

Instead of removing the log entirely, consider making it conditional:

const reportError = (error: Error) => {
  if (throwJsErrors) {
    console.error('Error in RSC stream', error);
    emitError(error);
  }
  renderState.hasErrors = true;
  renderState.error = error;
};

This maintains observability when errors are being thrown while reducing noise in test scenarios.

2. PR Checklist Items

The PR description mentions these items are unchecked:

  • Add/update test to cover these changes
  • Update documentation
  • Update CHANGELOG file

Suggestions:

  • Tests: Consider adding a test that verifies no console output occurs during RSC error handling when throwJsErrors: false (similar to the existing console leak tests)
  • Documentation: Not critical for this change, but if error handling behavior is documented anywhere, ensure it's accurate
  • CHANGELOG: Add an entry like:
    ### Fixed
    - Reduced console noise during RSC error handling by removing redundant console.error call [[#1892](https://github.com/shakacode/react_on_rails/pull/1892)]
    

3. Test Coverage Analysis

Looking at serverRenderRSCReactComponent.rsc.test.tsx, the existing tests focus on:

  • Log isolation between concurrent renders
  • Log capture during stream reading

Missing test coverage:

  • Error scenarios with throwJsErrors: true/false
  • Verification that error state is properly set without console logging
  • Confirmation that the failing rspec test now passes

Consider adding a test like:

test('errors are handled without console logging', async () => {
  const consoleErrorSpy = jest.spyOn(console, 'error');
  // ... render component that triggers an error with throwJsErrors: false
  expect(consoleErrorSpy).not.toHaveBeenCalledWith('Error in RSC stream', expect.any(Error));
  consoleErrorSpy.mockRestore();
});

Potential Issues: ⚠️ Minor

Debugging impact: When investigating RSC rendering issues, developers will have one less data point (the console.error) to work with. Consider:

  • Adding debug-level logging that can be enabled via configuration
  • Documenting that throwJsErrors: true should be used during development for better error visibility

Performance: ✅ Neutral/Positive

Removing console.error calls has minimal performance impact but does reduce I/O operations, which is beneficial in high-throughput scenarios.

Security: ✅ No concerns

This change doesn't introduce security issues. It may actually improve security slightly by reducing information leakage through logs in production environments.

Overall Assessment: ✅ Approved with Suggestions

The change is valid and brings consistency to error handling across the codebase. However, the PR would be stronger with:

  1. Test coverage demonstrating the fix
  2. CHANGELOG entry
  3. Consideration of conditional logging for better observability

Questions:

  1. Which specific rspec test was failing, and can you confirm it now passes?
  2. Was the console.error causing test pollution/noise that made assertions fail?
  3. Have you considered the debugging implications for production issues?

@AbanoubGhadban AbanoubGhadban force-pushed the fix-failing-rspec-test-for-non-hydrated-streamed-page branch from 2e2c532 to f8d1dbc Compare November 1, 2025 18:26
@claude
Copy link

claude bot commented Nov 1, 2025

Code Review

Thank you for this PR! I've reviewed the changes and have some feedback below.

Overview

This PR addresses a failing RSpec test for non-hydrated streamed pages by making three key changes:

  1. Removing a console.error call during RSC stream error handling
  2. Fixing a regex escape issue in the test script
  3. Increasing timeout values in the test configuration

Detailed Feedback

Positive Changes

1. Removal of console.error (ReactOnRailsRSC.ts:58)

  • Good: Removing the console.error reduces console noise and aligns with the error handling strategy already in place
  • Good: The error is still properly tracked via renderState.hasErrors = true and renderState.error = error
  • Good: The conditional error reporting based on throwJsErrors flag is maintained
  • This is a sensible change that cleans up logging while maintaining proper error state management

2. Regex fix in package.json test script

  • Good: The regex pattern ".*\\.rsc\\.test\\..*" is now properly escaped (previously ".*(.rsc.test.).*")
  • Good: This ensures the test filtering works correctly and only non-RSC tests are run
  • The old pattern had incorrect parentheses instead of escaped dots, which could cause test filtering issues

⚠️ Concerns & Questions

1. Timeout Configuration Changes (react_on_rails_pro.rb)

-  config.ssr_timeout = 10
+  config.renderer_http_pool_timeout = 20
+  config.ssr_timeout = 30

Concern: The commit message says "revert this: increase ssr timeout", suggesting these timeout increases are temporary

  • Are these timeout increases necessary for the fix, or are they a workaround for an underlying performance issue?
  • Tripling the ssr_timeout from 10 to 30 seconds is significant. Is there a root cause that should be investigated?
  • The addition of renderer_http_pool_timeout = 20 is new - what prompted this?
  • Recommendation: If these are temporary workarounds, add a TODO comment explaining why and when they should be reverted

2. Missing PR Checklist Items

The PR template checklist is unchecked:

  • Add/update test to cover these changes
  • Update documentation
  • Update CHANGELOG file

Questions:

  • Are there test changes that demonstrate the fix works?
  • Should the CHANGELOG be updated to document this bug fix?
  • Should any documentation be updated regarding error handling behavior?

3. Error Handling Flow Clarification

Looking at ReactOnRailsRSC.ts:57-63, the reportError function:

const reportError = (error: Error) => {
  if (throwJsErrors) {
    emitError(error);
  }
  renderState.hasErrors = true;
  renderState.error = error;
};

Question: With the console.error removed, how will developers debug RSC stream errors during development? Consider:

  • Adding a debug mode that logs errors
  • Or documenting that developers should check throwJsErrors configuration for error visibility

🔍 Testing Recommendations

  1. Verify the specific test case: Can you confirm which RSpec test was failing and that it now passes?
  2. Test error scenarios: Ensure that with throwJsErrors: false, errors are still properly tracked in renderState
  3. Test error scenarios: Ensure that with throwJsErrors: true, errors are properly emitted to the stream
  4. Timeout necessity: Test whether the timeout increases are truly needed or if they can be reduced

📋 Code Quality

  • Style: Changes follow existing code patterns ✓
  • TypeScript: No type safety issues ✓
  • Error handling: Maintains existing error handling contracts ✓
  • Performance: The timeout increases may impact test performance

Summary

Approve with reservations. The core changes (removing console.error and fixing the regex) are solid improvements. However, please address:

  1. ⚠️ Critical: Clarify the timeout increases - are they permanent or temporary? Document if temporary.
  2. 📝 Important: Complete the PR checklist items (tests, CHANGELOG, docs)
  3. 💡 Suggestion: Consider adding a comment about error visibility for debugging

Once these items are addressed, this will be a clean bug fix. Great work on reducing console noise while maintaining proper error state!

@claude
Copy link

claude bot commented Nov 1, 2025

Code Review for PR #1892: Fix failing rspec test for non hydrated streamed page

Summary

This PR makes three key changes:

  1. Removes a console.error call from RSC stream error handling
  2. Fixes a regex pattern in test configuration
  3. Increases timeout values and disables retry logic in test configuration

Detailed Review

1. Code Quality & Best Practices

✅ Positive:

  • The regex fix in package.json is correct - properly escaping dots in the pattern (\.rsc\.test\.) prevents unintended matches
  • The removal of console.error aligns with the PR description's goal of "reducing console noise"
  • Code changes are minimal and focused

⚠️ Concerns:

  • The console.error removal (ReactOnRailsRSC.ts:58) removes potentially valuable debugging information. The error is still tracked in renderState.error and can be emitted if throwJsErrors is true, but developers won't see errors in the console when throwJsErrors is false
  • Consider: This might make debugging harder in development environments where throwJsErrors: false

Recommendation: Consider adding a conditional console.error for development environments:

const reportError = (error: Error) => {
  if (throwJsErrors) {
    emitError(error);
  } else if (process.env.NODE_ENV !== 'production') {
    console.error('Error in RSC stream', error);
  }
  renderState.hasErrors = true;
  renderState.error = error;
};

2. Configuration Changes (react_on_rails_pro.rb)

⚠️ Significant Concerns:

The timeout and retry changes appear to be test-specific workarounds rather than proper fixes:

# Before
config.ssr_timeout = 10
config.renderer_request_retry_limit = 1

# After  
config.renderer_http_pool_timeout = 20
config.ssr_timeout = 30
config.renderer_request_retry_limit = 0

Issues:

  1. Tripled timeout (10s → 30s): This masks underlying performance issues rather than fixing them
  2. Disabled retries (1 → 0): Reduces resilience to transient failures
  3. Added new timeout: renderer_http_pool_timeout = 20 adds another layer without clear justification
  4. Test configuration in production config file: The file spec/dummy/config/initializers/react_on_rails_pro.rb is a test dummy app, but these values might be copied by users

Questions:

  • Why did the original timeout of 10s become insufficient?
  • What is the root cause of the test failures? Is it:
    • Slow CI environment?
    • Actual rendering performance regression?
    • Test flakiness?
  • Why disable retries entirely rather than adjusting retry logic?

Recommendation:

  • Investigate the root cause rather than increasing timeouts
  • Document why these specific values were chosen
  • Consider environment-specific configuration (test vs production)

3. Test Coverage

❌ Missing:

  • No new tests added despite the checklist item
  • No test file changes visible in the PR
  • The PR title mentions "Fix failing rspec test" but no test modifications are shown

Questions:

  • Which specific test was failing?
  • How do we verify this fix prevents future regressions?
  • Were the tests run and passing after these changes?

Recommendation:

  • Show evidence that the failing test now passes
  • Add a test case that would have caught this regression
  • Consider adding integration tests for the streaming error scenarios

4. Performance Considerations

⚠️ Concerns:

  • The 3x timeout increase (10s → 30s) could significantly impact user experience if timeouts actually occur
  • renderer_http_pool_timeout = 20 suggests connection pool issues that should be investigated
  • No benchmarks or performance metrics provided

Recommendation:

  • Profile the rendering to identify bottlenecks
  • Consider if the timeout increases indicate a need for:
    • Connection pool tuning
    • Renderer process optimization
    • Better resource allocation in CI

5. Security Concerns

✅ No security issues identified

  • Changes don't introduce security vulnerabilities
  • Error handling still prevents information leakage

6. Documentation & Process Issues

❌ Missing:

  • CHANGELOG entry (mentioned in checklist but not added)
  • PR description is still using template placeholders
  • No explanation of:
    • Which test was failing
    • Why it was failing
    • How these changes fix it
    • Impact on real-world usage

⚠️ Code Review shows the PR body still contains:

"Remove this paragraph and provide a general description..."

7. Potential Bugs

🔍 Worth investigating:

  1. The combination of increased timeouts + disabled retries suggests the underlying issue isn't resolved
  2. Removing console.error without alternative logging might hide real errors in production
  3. The regex fix is good, but it's unclear if this was causing test failures or if it's a separate fix

Recommendations Summary

High Priority:

  1. Complete the PR description - explain what was failing and why these changes fix it
  2. Add CHANGELOG entry as required by checklist
  3. Investigate root cause - Don't just increase timeouts, find out why renders are slow
  4. Add/verify test coverage - Show which test failed and that it now passes

Medium Priority:
5. Consider conditional error logging for development environments
6. Document the reasoning behind specific timeout values
7. Re-evaluate disabling retries entirely
8. Add performance benchmarks if this relates to rendering performance

Low Priority:
9. Consider extracting timeout configurations to environment variables
10. Add comments explaining the rationale for these specific timeout values

Questions for the Author

  1. Which specific RSpec test was failing before these changes?
  2. Can you share the test failure output?
  3. What is the root cause - slow CI, renderer performance, or test flakiness?
  4. Have you verified these changes don't negatively impact production environments?
  5. Why was the retry logic disabled entirely rather than adjusted?

Conclusion

While the regex fix is good and the intent to reduce console noise is valid, the configuration changes appear to be treating symptoms rather than addressing root causes. This PR needs:

  • Better documentation
  • Investigation of why timeouts need to triple
  • Test evidence showing the fix works
  • CHANGELOG entry

Status: ⚠️ Needs Revision - Please address the documentation and investigate the root cause before merging.


Review generated with assistance from Claude Code

@claude
Copy link

claude bot commented Nov 2, 2025

Code Review: PR #1892 - Fix failing rspec test for non hydrated streamed page

Overview

This PR makes several changes to fix a failing rspec test related to non-hydrated streamed pages. The changes span timeout configurations, error logging, and test patterns.


🔴 Critical Issues

1. Hardcoded Timeout Values in Production Code (request.rb:247-253)

The most concerning change is hardcoding ALL timeout values to 100 seconds in request.rb:

timeout: {
  connect_timeout: 100,
  read_timeout: 100,
  write_timeout: 100,
  request_timeout: 100,
  operation_timeout: 100,
  keep_alive_timeout: 100,
}

Issues:

  • Ignores configuration: Previously used ReactOnRailsPro.configuration.renderer_http_pool_timeout and ReactOnRailsPro.configuration.ssr_timeout
  • Magic numbers: No explanation for why 100 seconds
  • Inconsistent with dummy app config: Dummy app sets ssr_timeout = 30 and renderer_http_pool_timeout = 20, but production code ignores these
  • Not configurable: Users cannot override these values

This appears to be debug/test code that shouldn't be committed to production.

Recommendation: Revert to using configuration values:

timeout: {
  connect_timeout: ReactOnRailsPro.configuration.renderer_http_pool_timeout,
  read_timeout: ReactOnRailsPro.configuration.ssr_timeout,
  # ... other timeouts based on appropriate config values
}

2. Incomplete PR Checklist

The PR description still contains template placeholders and all checklist items are unchecked:

  • Add/update test to cover these changes
  • Update documentation
  • Update CHANGELOG file

Per CLAUDE.md requirements, these MUST be completed before merging.


⚠️ Significant Concerns

3. Removed Error Logging (ReactOnRailsRSC.ts:58)

The removal of console.error('Error in RSC stream', error); reduces observability:

Impact:

  • When throwJsErrors: false, errors now fail silently
  • Harder to debug RSC rendering issues in production
  • Inconsistent with general best practices for error visibility

Suggestion: Consider environment-aware logging:

if (process.env.NODE_ENV === 'development' || throwJsErrors) {
  console.error('Error in RSC stream', error);
}
if (throwJsErrors) {
  emitError(error);
}

4. Test Retry Limit Set to 0

Changed renderer_request_retry_limit from 1 to 0 in the dummy app config.

Questions:

  • Why disable retries? This makes tests less resilient to transient failures
  • Is this related to the test timeout? If so, the root cause should be addressed instead

5. Increased Timeout Values

Dummy app config changes:

  • renderer_http_pool_timeout: 20 (was implicit default of 5)
  • ssr_timeout: 30 (was 10)

Concerns:

  • Why such large increases? This suggests the underlying rendering is very slow
  • Tests will now take 3x longer to timeout
  • May mask performance issues rather than fixing them

✅ Good Changes

6. Fixed Test Pattern Regex (package.json:11)

-"test:non-rsc": "jest tests --testPathIgnorePatterns=\".*(.rsc.test.).*\"",
+"test:non-rsc": "jest tests --testPathIgnorePatterns=\".*\\.rsc\\.test\\..*\"",

Good: Properly escapes dots in the regex pattern. The original pattern (.rsc.test.) would match any character instead of literal dots.


📋 Required Actions Before Merge

Per CLAUDE.md and repository standards:

  1. Revert hardcoded timeouts in request.rb - Use configuration values instead
  2. Fill out PR description - Explain what test was failing and root cause
  3. Update CHANGELOG.md - Add entry at the top explaining these changes
  4. Add test coverage - Verify the fix works and prevent regression
  5. Run linting: bundle exec rubocop and fix ALL violations (per CLAUDE.md)
  6. Explain timeout increases - Why are such large timeouts needed?
  7. Consider logging strategy - Should RSC errors be visible in development?

🎯 Root Cause Analysis Needed

The PR title says "fix failing rspec test" but doesn't explain:

  • Which test was failing?
  • What was the failure mode? (timeout? unexpected console output? race condition?)
  • Why do these changes fix it?

Without this context, it's impossible to verify that:

  1. The fix addresses the root cause vs. masking symptoms
  2. The fix won't cause regressions elsewhere
  3. The fix is the minimal necessary change

💡 Recommendations

  1. Investigate the root cause of slow rendering that requires 30s+ timeouts
  2. Profile the test to understand why it needs such high timeout values
  3. Consider test-only configuration if these values are only needed for one specific test
  4. Keep production code configurable - don't hardcode timeout values
  5. Add documentation explaining the error logging strategy for RSC

🚦 Review Status: CHANGES REQUESTED

Cannot approve due to:

  1. 🔴 Hardcoded timeout values in production code
  2. 🔴 Incomplete PR checklist
  3. 🔴 Missing CHANGELOG entry
  4. ⚠️ Insufficient context about what test was failing and why

Please address the critical issues and required actions before requesting re-review.


References

  • Repository guidelines: CLAUDE.md (especially formatting and commit requirements)
  • Timeout defaults: react_on_rails_pro/lib/react_on_rails_pro/configuration.rb:44-46

@claude
Copy link

claude bot commented Nov 2, 2025

Code Review for PR #1892

Thank you for this PR! I've reviewed the changes and have several concerns and suggestions:


🚨 Critical Issues

1. Hardcoded Timeout Values (request.rb:247-252)

The changes replace configurable timeout values with hardcoded 100 (seconds) across all timeout parameters:

timeout: {
  connect_timeout: 100,
  read_timeout: 100,
  write_timeout: 100,
  request_timeout: 100,
  operation_timeout: 100,
  keep_alive_timeout: 100,
}

Problems:

  • Ignores user configuration: The original code used ReactOnRailsPro.configuration.renderer_http_pool_timeout and ReactOnRailsPro.configuration.ssr_timeout, which are user-configurable. Hardcoding these values completely bypasses configuration.
  • Excessive timeout values: 100 seconds is extremely high for HTTP operations. The default renderer_http_pool_timeout is 5 seconds and ssr_timeout is 5 seconds (per configuration.rb:44,46).
  • Inconsistent with other changes: You're increasing ssr_timeout to 30 in the test config, but then using 100 in the actual code?

Recommendation: This should use the configuration values properly:

timeout: {
  connect_timeout: ReactOnRailsPro.configuration.renderer_http_pool_timeout,
  read_timeout: ReactOnRailsPro.configuration.ssr_timeout,
  write_timeout: ReactOnRailsPro.configuration.ssr_timeout,
  request_timeout: ReactOnRailsPro.configuration.ssr_timeout,
  # ... etc
}

2. Missing PR Description

The PR body still contains placeholder text and doesn't explain:

  • What test was failing?
  • What was the root cause?
  • Why are these specific changes the correct fix?

Required: Please provide:

  • Description of the failing test
  • Stack trace or error message
  • Explanation of why each change is necessary

⚠️ Moderate Issues

3. Test Configuration Changes (spec/dummy/config/initializers/react_on_rails_pro.rb)

config.renderer_http_pool_timeout = 20  # was not explicitly set (default: 5)
config.ssr_timeout = 30                  # was 10
config.renderer_request_retry_limit = 0 # was 1

Concerns:

  • Disabling retries: Setting renderer_request_retry_limit = 0 might hide intermittent issues instead of fixing them. Why is this necessary?
  • Timeout increases: Why do tests need 3-6x longer timeouts? This could mask performance issues or indicate that the renderer is too slow.
  • Test environment specificity: These changes only affect the test dummy app. Do production apps need similar changes?

4. Removed Console Error (ReactOnRailsRSC.ts:58)

-    console.error('Error in RSC stream', error);

Concerns:

  • Silent failures: Removing this log means errors may go completely unnoticed in non-throwJsErrors mode.
  • Debugging difficulty: Console logs are valuable for debugging, especially in development.

Recommendation: Consider using a configurable logging approach:

const reportError = (error: Error) => {
  if (throwJsErrors) {
    emitError(error);
  } else {
    // Still log in development or when tracing is enabled
    console.error('Error in RSC stream', error);
  }
  renderState.hasErrors = true;
  renderState.error = error;
};

✅ Good Changes

5. Test Path Pattern Fix (package.json:11)

-"testPathIgnorePatterns=\".*(.rsc.test.).*\""
+"testPathIgnorePatterns=\".*\\.rsc\\.test\\..*\""

Good! This properly escapes the dots in the regex pattern, making it more precise.


📋 Missing Items from PR Checklist

  • ❌ Add/update test to cover these changes
  • ❌ Update documentation
  • ❌ Update CHANGELOG file

Please ensure these are completed before merging.


🔍 Questions

  1. What specific test was failing, and what was the exact error message?
  2. Have you verified that production apps won't be negatively affected by the hardcoded 100-second timeouts?
  3. Why is disabling retries (renderer_request_retry_limit = 0) necessary?
  4. Should the timeout configuration support different values for different timeout types (connect vs read vs write)?

📝 Recommendations

  1. Revert the hardcoded timeout values and properly use configuration settings
  2. Add a new configuration option if you need to control these timeouts separately
  3. Update the PR description with details about the failing test
  4. Consider a more nuanced logging approach instead of completely removing error logs
  5. Add tests that verify the timeout behavior works correctly
  6. Update documentation to explain any new configuration options

Would you like help implementing any of these suggestions?

@claude
Copy link

claude bot commented Nov 2, 2025

Pull Request Review

Summary

This PR addresses a failing RSpec test for non-hydrated streamed pages by making several configuration and error handling adjustments. The changes focus on reducing noise in console output and adjusting timeout/retry settings for better test reliability.


Code Quality & Best Practices

Good Practices:

  1. Regex Pattern Fix - The test ignore pattern in package.json was properly escaped:

    • Changed: ".*(.rsc.test.).*" to ".*\\.rsc\\.test\\..*"
    • This is a correct fix - the original pattern was not properly escaping dots, which would match any character instead of literal dots
  2. Reduced Console Noise - Removing console.error('Error in RSC stream', error) from ReactOnRailsRSC.ts:58 is reasonable since:

    • The error is still captured in renderState.hasErrors and renderState.error
    • When throwJsErrors is true, the error is emitted via emitError(error)
    • This prevents duplicate logging for expected error scenarios in tests
  3. Removed Automatic Retries - Removing the .plugin(:retries, max_retries: 1, retry_change_requests: true) line in request.rb:230 is sensible because:

    • Manual retry logic already exists in perform_request method (lines 89-123)
    • Controlled via renderer_request_retry_limit configuration
    • Avoids double-retry scenarios that could cause confusion

⚠️ Concerns:

  1. Missing PR Description - The PR template placeholders were not filled in:

    • No description of the actual failing test
    • No explanation of root cause
    • No information about what changes fix the issue
    • Action needed: Please fill in the Summary, what bug was fixed, and why these changes resolve it
  2. Missing Test Coverage - The checklist shows unchecked items:

    • [ ] Add/update test to cover these changes
    • Question: Are there new tests to verify this fix? Or do existing tests now pass?
    • Action needed: Either add tests or document which existing tests now pass
  3. Missing CHANGELOG Entry - Per CLAUDE.md requirements and the PR checklist:

    • The [ ] Update CHANGELOG file box is unchecked
    • Action needed: Add entry to CHANGELOG.md under Unreleased > Bug Fixes section following the format:
    - **Fix failing RSpec test for non-hydrated streamed pages**: [Brief description of fix]. [PR #1892](https://github.com/shakacode/react_on_rails/pull/1892) by [AbanoubGhadban](https://github.com/AbanoubGhadban).
  4. Large Timeout Increase - Test configuration changes are significant:

    • ssr_timeout: 10 → 30 seconds (200% increase)
    • renderer_http_pool_timeout: default → 20 seconds (newly added)
    • Concern: These are test-only settings, but such large increases might hide underlying performance issues
    • Question: Is there a legitimate reason the test needs 30 seconds? Could this indicate a problem with the test itself or the code under test?
  5. Retry Limit Changed - Setting renderer_request_retry_limit: 0 in test config:

    • This disables retries completely in tests
    • Question: Is this intentional to make tests faster/more deterministic? Or does the test fail with retries enabled?
    • Suggestion: Add a code comment explaining why retries are disabled in tests

Potential Bugs or Issues

  1. Silent Error Swallowing Risk - Removing the console.error line in ReactOnRailsRSC.ts:58:

    const reportError = (error: Error) => {
    // console.error('Error in RSC stream', error); // REMOVED
    if (throwJsErrors) {
    emitError(error);
    }
    renderState.hasErrors = true;
    renderState.error = error;
    };

    - **Issue**: When `throwJsErrors` is `false`, errors are now completely silent
    - **Risk**: Debugging issues in production could be harder
    - **Suggestion**: Consider conditional logging:
    ```typescript
    const reportError = (error: Error) => {
      if (throwJsErrors) {
        emitError(error);
      } else {
        // Only log when not throwing to avoid duplicate errors
        console.error('Error in RSC stream', error);
      }
      renderState.hasErrors = true;
      renderState.error = error;
    };
    
  2. Test-Specific Configuration Leakage - The changes in spec/dummy/config/initializers/react_on_rails_pro.rb are test-specific:

    • These high timeout values should NOT be copied to production configs
    • Suggestion: Add a comment warning developers not to copy these values to their apps

Performance Considerations

  1. Timeout Values - The 30-second SSR timeout is quite high:

    • Most SSR should complete in <5 seconds for good UX
    • Question: What's causing the test to need so long? Is there a way to optimize the test setup instead?
  2. No Retries in Tests - Setting retries to 0 improves test speed:

    • ✅ This is good for test performance and determinism
    • ✅ Tests should fail fast rather than retry

Security Concerns

No security issues identified in this PR.


Test Coverage

Missing Information:

  • Which specific test was failing?
  • Does this test now pass with these changes?
  • Are there new tests to prevent regression?

Required Actions:

  1. Document which test(s) were failing
  2. Confirm all tests now pass
  3. Consider adding a regression test if one doesn't exist

Formatting & Style

According to CLAUDE.md requirements, you must:

  1. BEFORE COMMITTING: Run bundle exec rubocop and fix ALL violations
  2. BEFORE COMMITTING: Ensure all files end with a newline character
  3. FORMATTING: Run rake autofix to ensure Prettier/RuboCop formatting

Action needed: Please confirm these have been run.


Summary of Required Actions

High Priority:

  1. ✅ Fill in PR description with actual summary of changes and bug fix
  2. ✅ Add CHANGELOG entry under Unreleased > Bug Fixes
  3. ✅ Document which test was failing and confirm it passes now
  4. ✅ Run bundle exec rubocop and fix any violations
  5. ✅ Run rake autofix for formatting

Medium Priority:
6. Consider conditional logging in ReactOnRailsRSC.ts to avoid silent errors when throwJsErrors = false
7. Add comment in test config explaining why retries are disabled
8. Add warning comment about not copying high timeout values to production
9. Investigate if 30-second timeout is truly necessary or if test can be optimized

Nice to Have:
10. Add regression test if one doesn't exist
11. Document root cause analysis in PR description


Overall Assessment

The technical changes look reasonable and address legitimate issues:

  • ✅ Regex escaping fix
  • ✅ Removing duplicate retry logic
  • ✅ Reducing console noise in tests

However, the PR needs significant documentation improvements before merging:

  • Missing description
  • Missing CHANGELOG entry
  • Missing test documentation
  • Unchecked checklist items

Recommendation: Request changes - ask the author to complete the documentation and checklist items before merging.

@claude
Copy link

claude bot commented Nov 2, 2025

Pull Request Review - PR #1892

Thank you for working on fixing the failing RSpec test! I've reviewed the changes and have several concerns and recommendations:


Critical Issues

1. Hardcoded Timeout Values in Production Code

Location: react_on_rails_pro/lib/react_on_rails_pro/request.rb:256-262

All timeout values are hardcoded to 100 seconds, completely ignoring the configuration values. This overrides ReactOnRailsPro.configuration.renderer_http_pool_timeout and will mask real timeout issues. This appears to be a debugging workaround that shouldn't be committed.

Recommendation: Either use the configuration values properly or create new configuration options if needed.

2. Disabled Retry Logic Without Clear Justification

Location: react_on_rails_pro/spec/dummy/config/initializers/react_on_rails_pro.rb:39

Changed from renderer_request_retry_limit = 1 to 0, disabling retries entirely. The PR description mentions an EOFError but doesn't explain why disabling retries fixes it. This may mask the underlying connection issue.

Recommendation: Investigate the root cause of the EOF error instead of disabling retries.

3. Overly Verbose Retry Logging

Location: react_on_rails_pro/lib/react_on_rails_pro/request.rb:233-237

The retry callback logs at ERROR level for every retry attempt and logs request bodies which could expose sensitive data. Has typo: occured should be occurred. The lambda always returns 0 which could cause infinite retry loops without max_retries.

Recommendation: Use appropriate log levels and add max_retries configuration.


Moderate Issues

4. Removed Error Logging in Critical Path

Location: packages/react-on-rails-pro/src/ReactOnRailsRSC.ts:57-63

Removed console.error from the error handler, reducing error visibility. Debugging stream-related issues will be harder.

Recommendation: Consider environment-based conditional logging instead of removing it entirely.

5. Test Configuration Changes

Location: react_on_rails_pro/spec/dummy/config/initializers/react_on_rails_pro.rb

Multiple timeout configurations changed without clear explanation of why these specific values were chosen or whether they should apply to production.


Good Changes

6. Fixed Test Path Pattern

Location: packages/react-on-rails-pro/package.json:11

Changed from .(.rsc.test.). to ..rsc.test.. - This properly escapes the dots in the regex pattern. Good fix!


Missing Information

  • Clear explanation of the EOFError: descriptor closed issue
  • Root cause analysis
  • Test coverage for the fix
  • CHANGELOG entry (required by PR checklist)
  • Documentation of why each change is necessary

Recommendations Summary

Before merging:

  1. Revert hardcoded timeouts - Use configuration values or create new config options
  2. Re-enable retries with proper configuration, or document why they must be disabled
  3. Restore error logging with environment-based conditional logic
  4. Fix retry callback to use appropriate log levels and add max_retries
  5. Update PR description with root cause analysis
  6. Add test coverage to prevent regression
  7. Update CHANGELOG as required
  8. Run bundle exec rubocop to ensure linting passes

Alternative approach: Investigate if the EOF error is caused by connection pooling issues, stream handling problems in the test environment, or race conditions in cleanup code. These changes feel like they're working around symptoms rather than fixing root causes.

Let me know if you'd like help investigating the root cause!

@claude
Copy link

claude bot commented Nov 2, 2025

Code Review for PR #1892

Summary: This PR addresses an EOFError by making timeout/retry configuration changes and removing error logging. However, there are several critical concerns.

Critical Issues

1. Hardcoded Timeout Values (BLOCKING) - react_on_rails_pro/lib/react_on_rails_pro/request.rb:256-263
All timeouts hardcoded to 100ms, ignoring configuration. This removes flexibility for production users and conflicts with test config that sets renderer_http_pool_timeout=20 and ssr_timeout=30.

2. Debug Code in Production (BLOCKING) - react_on_rails_pro/lib/react_on_rails_pro/request.rb:234-239
Contains debugging logs with typo (occured), logs full request bodies (security risk), and appears to be temporary debugging code.

3. Silenced Error Logging - packages/react-on-rails-pro/src/ReactOnRailsRSC.ts:57-63
Removes console.error without explanation. Errors now only logged if throwJsErrors is true, making debugging harder.

4. Disabled Retries in Tests - config/initializers/react_on_rails_pro.rb:39
Sets renderer_request_retry_limit=0, masking potential flakiness and creating inconsistency with production.

Other Concerns

  • Increased timeouts without justification (may slow tests)
  • Incomplete PR checklist (no tests, docs, or CHANGELOG)
  • Vague description (doesn't explain root cause or how fix works)
  • Security: Request body logging could leak sensitive data

Questions

  1. What is the root cause of EOFError: descriptor closed?
  2. Why 100ms for all timeouts?
  3. Why disable retries in tests?
  4. Have you verified this actually fixes the failure?

Recommendation

Request changes. The hardcoded timeouts and debug logging are blocking issues. Please clarify root cause and provide a more targeted fix that uses configuration properly.

Note: The regex fix in package.json is good but appears unrelated to the bug fix.

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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
react_on_rails_pro/lib/react_on_rails_pro/request.rb (1)

257-263: Consider using configuration values instead of hardcoded timeouts.

All timeout values are hardcoded to 100 seconds, which removes the ability to configure timeouts dynamically per environment. This is inconsistent with the gem's configuration pattern used elsewhere (e.g., renderer_http_pool_size at line 249).

Note that the error message handler at lines 268-270 still references renderer_http_pool_timeout, creating an inconsistency.

Consider using configuration values:

           timeout: {
-            connect_timeout: 100,
-            read_timeout: 100,
-            write_timeout: 100,
-            request_timeout: 100,
-            operation_timeout: 100,
-            keep_alive_timeout: 100,
+            connect_timeout: ReactOnRailsPro.configuration.renderer_connect_timeout,
+            read_timeout: ReactOnRailsPro.configuration.renderer_read_timeout,
+            write_timeout: ReactOnRailsPro.configuration.renderer_write_timeout,
+            request_timeout: ReactOnRailsPro.configuration.renderer_request_timeout,
+            operation_timeout: ReactOnRailsPro.configuration.renderer_operation_timeout,
+            keep_alive_timeout: ReactOnRailsPro.configuration.renderer_keep_alive_timeout,
           }

If hardcoded values are intentional for this PR to fix the failing test, consider adding a TODO comment explaining the rationale and plan for making these configurable in the future.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1374927 and 3c1cd48.

📒 Files selected for processing (1)
  • react_on_rails_pro/lib/react_on_rails_pro/request.rb (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}

📄 CodeRabbit inference engine (CLAUDE.md)

{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}: All Ruby code must pass RuboCop with zero offenses before commit/push
RuboCop is the sole authority for Ruby file formatting; never manually format Ruby files

Files:

  • react_on_rails_pro/lib/react_on_rails_pro/request.rb
🧠 Learnings (1)
📓 Common learnings
Learnt from: alexeyr-ci
Repo: shakacode/react_on_rails PR: 1644
File: node_package/src/ReactOnRailsRSC.ts:87-87
Timestamp: 2024-12-12T13:07:09.929Z
Learning: When handling errors in 'node_package/src/ReactOnRailsRSC.ts', include the error stack in error messages in development and test environments to aid debugging.

Comment on lines 234 to 239
retry_after: ->(req, res) do
Rails.logger.error("An error occured and retry is going to be made")
Rails.logger.error("Error: #{res.error}")
Rails.logger.error("Request Body: #{req.body}")
0
end,
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid logging request body due to security and privacy risks.

The retry_after hook unconditionally logs the full request body, which may contain sensitive information such as rendering code, form data, PII, or secrets. This creates a compliance and security risk.

Additionally, the hook always returns 0 (immediate retry) regardless of the error type, which could cause inappropriate retry behavior for non-transient errors and lacks backoff strategy.

Minor: Line 235 has a typo—"occured" should be "occurred".

Consider these improvements:

           retry_after: ->(req, res) do
-            Rails.logger.error("An error occured and retry is going to be made")
+            Rails.logger.error("An error occurred and retry is going to be made")
             Rails.logger.error("Error: #{res.error}")
-            Rails.logger.error("Request Body: #{req.body}")
+            # Avoid logging request body due to potential sensitive data
+            Rails.logger.debug("Request path: #{req.path}") if Rails.env.development?
             0
           end,

Also, consider implementing conditional retry logic based on error type (e.g., only retry on transient errors like connection failures, not on 4xx client errors).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
retry_after: ->(req, res) do
Rails.logger.error("An error occured and retry is going to be made")
Rails.logger.error("Error: #{res.error}")
Rails.logger.error("Request Body: #{req.body}")
0
end,
retry_after: ->(req, res) do
Rails.logger.error("An error occurred and retry is going to be made")
Rails.logger.error("Error: #{res.error}")
# Avoid logging request body due to potential sensitive data
Rails.logger.debug("Request path: #{req.path}") if Rails.env.development?
0
end,
🤖 Prompt for AI Agents
In react_on_rails_pro/lib/react_on_rails_pro/request.rb around lines 234–239,
the retry_after hook currently logs the full request body (a security/privacy
risk), has a typo ("occured"), and always returns 0 (immediate retry) regardless
of error type; change it to stop logging req.body and instead log non-sensitive
metadata (e.g., request path, method, and sanitized headers) and the error
message/class, correct the typo to "occurred", and implement conditional
retry/backoff: inspect the response/error (status code or exception class) and
only return a retry delay for transient errors (e.g., network/5xx) — use an
exponential backoff strategy (or nil/false for no retry) for non-transient
errors such as 4xx client errors.

@claude
Copy link

claude bot commented Nov 2, 2025

PR Review: Fix failing rspec test for non hydrated streamed page

Summary

This PR aims to fix an EOFError: descriptor closed issue in RSC streaming tests by adjusting timeouts, removing retry logic, removing a console.error statement, and fixing a regex pattern in test configuration.


Code Quality & Best Practices

✅ Positive Changes

  1. Test Pattern Fix (packages/react-on-rails-pro/package.json:11)

    • Before: ".*(.rsc.test.).*"
    • After: ".*\\.rsc\\.test\\..*"
    • This correctly escapes the dots in the regex pattern, which is the proper way to match literal dots in filenames.
  2. Reduced Console Noise (packages/react-on-rails-pro/src/ReactOnRailsRSC.ts:57-60)

    • Removed unconditional console.error('Error in RSC stream', error) statement
    • Error is still tracked in renderState.hasErrors and renderState.error
    • Errors are still emitted when throwJsErrors is true
    • This is reasonable for reducing noise in test output

⚠️ Concerns

  1. Hardcoded Timeout Values (react_on_rails_pro/lib/react_on_rails_pro/request.rb:246-251)

    • Issue: All timeouts are hardcoded to 100 seconds, ignoring the configuration values
    • Previous behavior: Used renderer_http_pool_timeout and ssr_timeout from config
    • Problem: This completely bypasses the configuration system and error message at line 258 still references the config values that are no longer being used
    • Recommendation: If the config values are insufficient, they should be updated, but hardcoding defeats the purpose of having configuration
  2. Removed Retry Logic (react_on_rails_pro/lib/react_on_rails_pro/request.rb:230)

    • Removed: .plugin(:retries, max_retries: 1, retry_change_requests: true)
    • Concern: This was handling transient connection failures for persistent connections
    • Impact: The application will now fail immediately on connection drops instead of retrying once
    • Question: Is this removal intentional or a workaround for the test failure? The comment on lines 227-229 explains why retries were needed.
  3. Test-Specific Configuration Changes (react_on_rails_pro/spec/dummy/config/initializers/react_on_rails_pro.rb:27-39)

    • Changed renderer_http_pool_timeout from implicit default (5) to 20
    • Changed ssr_timeout from 10 to 30
    • Changed renderer_request_retry_limit from 1 to 0
    • Concern: These changes only affect the test environment, but the production code has hardcoded timeouts that override these anyway

Potential Bugs

  1. Configuration Mismatch: The error message at request.rb:258-259 will display incorrect values since the actual timeouts are hardcoded

  2. Loss of Resilience: Removing retries without understanding the root cause may lead to increased failure rates in production, poor user experience when temporary network hiccups occur, and harder-to-debug intermittent failures


Performance Considerations

  1. Timeout Values: 100-second timeouts are very long and could cause requests to hang for extended periods, block connection pools, lead to poor user experience, and mask underlying performance issues

  2. No Retry Logic: While this may reduce latency in failure scenarios, it also reduces reliability


Test Coverage

Major Concern: The PR checklist indicates none of the items are checked. We don't know if this actually fixes the failing test, there's no explanation of WHY these changes fix the issue, no documentation of the root cause, and the PR description still has placeholder text.


Recommendations

  1. Understand Root Cause: Before merging, investigate why the EOFError: descriptor closed is happening and why these specific changes fix it

  2. Fix Configuration System: Use config values instead of hardcoded timeouts

  3. Reconsider Retry Removal: If retries are causing issues, document why in code comments and consider keeping retries but with different configuration

  4. Complete PR Checklist: Add tests that verify the fix, update CHANGELOG.md, fill out the PR description with actual details

  5. Consider Separate Concerns: This PR mixes regex fix (good), timeout changes (questionable), retry removal (risky), and console.error removal (reasonable) - consider splitting into separate PRs


Questions for Author

  1. What specific test was failing and how does this fix it?
  2. Why were 100-second timeouts chosen?
  3. What is the impact of removing retry logic in production?
  4. Have you verified this works with actual remote renderers, not just tests?
  5. Is the hardcoded timeout a temporary workaround or intended behavior?

Verdict

Status: ⚠️ Needs Work

While the regex fix is good and removing console noise is reasonable, the hardcoded timeouts and removed retry logic raise significant concerns. The PR appears to be a "make the test pass" approach rather than addressing the root cause. Please provide more context and consider the recommendations above before merging.

@claude
Copy link

claude bot commented Nov 2, 2025

Code Review for PR #1892

Thank you for working on fixing the failing rspec test issue. I've reviewed the changes and have comprehensive feedback.

🔴 Critical Issues

1. Typo in Error Message (react_on_rails_pro/lib/react_on_rails_pro/request.rb:235)

Line has: An error occured but should be: An error occurred (double 'r')

2. Unclear Purpose and Incomplete Implementation

The PR references issue #1895 about "body duplication problem" but:

Questions:

  • What specific test was failing?
  • How does adding logging fix the test?
  • What does returning nil from retry_after mean in httpx?

@claude
Copy link

claude bot commented Nov 2, 2025

⚠️ Important Concerns

3. Security: Potential PII/Sensitive Data Exposure

This line logs request bodies which can expose sensitive data:

Rails.logger.error("Request Body: #{req.body&.first(1000)}")

Recommendations:

  • Only log in development: if Rails.env.development?
  • Or log only metadata (body size, content-type)
  • Or sanitize sensitive fields before logging

4. Missing Test Coverage

No tests were added to verify:

  • The retry behavior works correctly
  • The logging occurs when retries happen
  • The fix addresses the failing test

Add a test in react_on_rails_pro/spec/react_on_rails_pro/request_spec.rb that mocks a connection failure/EOF error and verifies retry + logging behavior.

@claude
Copy link

claude bot commented Nov 2, 2025

5. Code Quality: Undocumented Magic Behavior

The retry_after lambda has undocumented behavior. Issues:

  • No comment explaining what returning nil does
  • No explanation of when callback is invoked
  • Side effects (logging) but return value behavior unclear

Recommendation: Add inline comment explaining the httpx retry_after callback contract (when it is invoked, what return values mean, etc.)

@claude
Copy link

claude bot commented Nov 2, 2025

📋 Minor Issues

6. Inconsistent Error Logging Pattern

Looking at the codebase, most error logging uses multi-line messages or heredoc for clarity. Consider consolidating the three separate logger.error calls into one heredoc-style message with the [ReactOnRailsPro] prefix for consistency.

🔧 Required Actions Before Merge

  1. Fix the typo: occurred (not occured)
  2. Complete PR description: Explain what test was failing and how this fixes it
  3. Complete issue [Important] Fix the body duplication problem when an retry happen after a connection error #1895: Add reproduction steps and expected/actual behavior
  4. Add security safeguards: Do not log sensitive request bodies in production
  5. Add test coverage: Verify retry behavior works correctly
  6. Update CHANGELOG: Document the fix
  7. Run linting: Ensure bundle exec rubocop passes (per CLAUDE.md requirements)

@claude
Copy link

claude bot commented Nov 2, 2025

📚 Documentation Suggestions

The retry_after callback is not obvious to readers. Consider adding documentation:

  • Why retries are needed (persistent connection closures)
  • When retries occur (what errors trigger them)
  • How the retry_after callback works
  • What the return value means

✅ What is Good

  • Good identification that retry behavior needs visibility
  • Using the existing httpx retry plugin rather than rolling custom retry logic
  • Limiting logged body to 1000 chars to avoid log explosion

Overall Assessment: This PR needs more work before merging. The core idea of adding retry visibility is good, but the implementation has security concerns, missing tests, and unclear purpose. Please address the critical issues and complete the PR checklist.

Let me know if you need help with any of these items!

@claude
Copy link

claude bot commented Nov 2, 2025

Code Review: Fix failing rspec test for non hydrated streamed page

Thank you for working on this fix! I've reviewed the changes and have several observations and concerns:

Critical Issues

1. Typo in Error Messages

All three error log messages contain a typo: "occured" should be "occurred"

Lines: 115, 238

2. Missing Newlines at End of File

⚠️ CRITICAL: Per the project's CLAUDE.md requirements, all files MUST end with a newline character. This file appears to be missing the trailing newline and will cause CI failures.

Action Required: Add a newline at the end of request.rb

3. Incomplete PR Description

The PR description references issue #1895, but that issue template appears incomplete/not filled out. This makes it difficult to understand:

  • What specific test is failing
  • What the root cause is (the EOFError descriptor closed)
  • Why these logging additions fix the issue

Code Quality Issues

4. Debug Logging in Production Code

The changes add error-level logging for debugging purposes, but these will run in production:

Rails.logger.error("An error occured and react on rails retry is going to be made")
Rails.logger.error("Error: #{e}")
Rails.logger.error("Post Options: #{post_options}")

Concerns:

  • Sensitive Data Exposure: post_options may contain sensitive rendering request data, bundle contents, or form data
  • Log Pollution: These messages will fire on every retry (which is normal behavior)
  • Redundancy: Lines 115-117 duplicate information already logged on line 111-113 (info level)

Recommendation:

  • Use Rails.logger.debug instead of Rails.logger.error for diagnostic information
  • Sanitize logged data to avoid exposing sensitive information
  • Consider using conditional logging based on configuration (e.g., a debug mode flag)

5. Lambda Callback Side Effects

The retry_after callback (lines 237-242) has side effects (logging) but returns nil. While this appears intentional:

retry_after: ->(req, res) do
  Rails.logger.error("An error occured and retry is going to be made")
  Rails.logger.error("Error: #{res.error}")
  Rails.logger.error("Request Body: #{req.body&.to_s.first(1000)}")
  nil
end,

Concerns:

  • The callback is designed to return a delay value, but it's being used for logging instead
  • Request body truncation to 1000 chars may cut off important debugging info in multipart forms
  • Same issues with error-level logging and sensitive data exposure

6. Potential Body Duplication Issue

The PR title mentions "Fix the body duplication problem when a retry happen after a connection error" (issue #1895), but the code changes only add logging. There's no actual fix for body duplication visible in these changes.

Question: How does adding logging fix the body duplication issue? Is this PR incomplete?

Testing Concerns

7. No Test Coverage

The PR checklist shows:

  • Add/update test to cover these changes
  • Update documentation
  • Update CHANGELOG file

None of these are checked, yet the PR claims to fix a failing test. Where are:

  • Tests demonstrating the fix works
  • Tests preventing regression
  • Documentation explaining the issue and solution

Performance Considerations

8. String Conversion on Every Retry

req.body&.to_s.first(1000) converts the entire request body to a string before truncating. For large multipart form data (bundles, assets), this could be expensive.

Security Concerns

9. Logging Sensitive Information

Both retry handlers log request/response data that could contain:

  • Bundle source code
  • Authentication tokens in headers
  • Internal system paths
  • Server-side rendering code

Recommendation: Implement log sanitization or redaction for sensitive fields.

Recommendations

  1. Fix the typo: "occured" → "occurred"
  2. Add trailing newline to prevent CI failure
  3. Complete the PR description and issue [Important] Fix the body duplication problem when an retry happen after a connection error #1895 with:
    • Specific test that was failing
    • Root cause analysis
    • How logging fixes the issue (or is this PR incomplete?)
  4. Downgrade logging to debug level or make it configurable
  5. Add tests that demonstrate:
    • The bug being fixed
    • The retry behavior working correctly
    • No body duplication on retries
  6. Sanitize logged data to avoid exposing sensitive information
  7. Update CHANGELOG as required by project guidelines
  8. Consider: Is this PR actually complete? If it only adds logging for diagnosis, should it be marked as a partial fix?

Questions for Author

  1. What specific rspec test was failing?
  2. How does adding logging fix the body duplication issue?
  3. Have you verified this works with the actual failing test?
  4. Is there more work needed beyond logging?

Before merging:

  • Run bundle exec rubocop and fix all violations (per CLAUDE.md)
  • Ensure file ends with newline
  • Complete PR checklist items
  • Address sensitive data logging concerns

@AbanoubGhadban
Copy link
Collaborator Author

Closed after reaching the results posted at the description and will be solved after fixing theis issue
#1895

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants