[Pro] Prevent caching RSC renders with errors - #4804
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughBuffered and static RSC caching now observes streamed ChangesRSC cache error handling
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Caller
participant cached_buffered_stream_react_component
participant buffered_stream_react_component
participant RailsCache
Caller->>cached_buffered_stream_react_component: request cached render
cached_buffered_stream_react_component->>buffered_stream_react_component: stream chunks with on_chunk_errors
buffered_stream_react_component-->>cached_buffered_stream_react_component: rendered output and error state
cached_buffered_stream_react_component->>RailsCache: write only when no chunk has hasErrors true
RailsCache-->>Caller: cached or freshly rendered output
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryPrevents rejected React Server Component renders from being persisted while preserving existing cache-hit, tag-registration, nil-value, and race-condition behavior.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains. Important Files Changed
Sequence DiagramsequenceDiagram
participant Caller
participant Helper as Pro RSC Helper
participant Cache as Rails.cache
participant Renderer
Caller->>Helper: Render cached component
Helper->>Cache: fetch(cache_key)
alt Cache hit
Cache-->>Helper: Cached clean render
else Cache miss
Helper->>Renderer: Stream render
Renderer-->>Helper: HTML chunks + hasErrors
alt Any chunk has errors
Helper-->>Cache: Exit fetch before write
Helper-->>Caller: Return rejected render
else Clean render
Helper-->>Cache: Return value and write entry
Helper-->>Caller: Return clean render
end
end
Reviews (2): Last reviewed commit: "Document cache safety fix attribution" | Re-trigger Greptile |
Review SummaryWhat this PR does: Extends the fix from PR #4722 (streaming caches) to the two other Pro cache paths — Code quality / correctness
Test coverageStrong — the new Minor issues
Security / performance
Overall this is a solid, well-tested fix that mirrors the existing pattern from #4722 and closes a real cache-poisoning bug (#4723). The only concrete fix needed is the missing changelog PR link. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
react_on_rails_pro/app/helpers/react_on_rails_pro_helper.rb (1)
452-462: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicated stream-error-tracking logic between buffered and static RSC cache paths.
render_cached_buffered_stream_react_componentandrender_cached_static_rsc_componentboth build an identicalstream_has_errorsflag, anon_chunk_errorslambda, and acache_write_if: -> { !stream_has_errors }predicate. Since this triplet is exactly the mechanism that prevents error-containing renders from being cached, keeping it in one place reduces the risk of the two paths silently diverging on this correctness-sensitive logic in a future change.♻️ Suggested extraction
+ def with_stream_error_cache_write_if + stream_has_errors = false + on_chunk_errors = ->(chunk_has_errors) { stream_has_errors ||= chunk_has_errors == true } + yield(on_chunk_errors, -> { !stream_has_errors }) + end + def render_cached_buffered_stream_react_component(component_name, cache_options, render_options) - stream_has_errors = false - fetch_react_component(component_name, cache_options, cache_write_if: -> { !stream_has_errors }) do - options = render_options.merge( - props: yield, - skip_prerender_cache: true, - on_chunk_errors: ->(chunk_has_errors) { stream_has_errors ||= chunk_has_errors == true } - ) - buffered_stream_react_component(component_name, options) + with_stream_error_cache_write_if do |on_chunk_errors, cache_write_if| + fetch_react_component(component_name, cache_options, cache_write_if:) do + options = render_options.merge(props: yield, skip_prerender_cache: true, on_chunk_errors:) + buffered_stream_react_component(component_name, options) + end end endAlso applies to: 641-658
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@react_on_rails_pro/app/helpers/react_on_rails_pro_helper.rb` around lines 452 - 462, Extract the shared stream-error tracking and cache-write predicate from render_cached_buffered_stream_react_component and render_cached_static_rsc_component into a common helper or wrapper. Update both methods to reuse that single mechanism while preserving the existing on_chunk_errors behavior and preventing cache writes when any stream error occurs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@CHANGELOG.md`:
- Around line 71-75: Update the new **[Pro]** changelog entry so its closing
attribution includes the required PR number/link and author link, matching the
`Fixes [Issue N]... [PR N](url) by [author](url).` format used by neighboring
entries. Preserve the existing issue reference and inline **[Pro]** marker.
---
Nitpick comments:
In `@react_on_rails_pro/app/helpers/react_on_rails_pro_helper.rb`:
- Around line 452-462: Extract the shared stream-error tracking and cache-write
predicate from render_cached_buffered_stream_react_component and
render_cached_static_rsc_component into a common helper or wrapper. Update both
methods to reuse that single mechanism while preserving the existing
on_chunk_errors behavior and preventing cache writes when any stream error
occurs.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 3c7ea805-7908-4e12-886d-f43bf1e39a1d
📒 Files selected for processing (3)
CHANGELOG.mdreact_on_rails_pro/app/helpers/react_on_rails_pro_helper.rbreact_on_rails_pro/spec/dummy/spec/helpers/react_on_rails_pro_helper_spec.rb
|
CodeRabbit review-summary disposition: the changelog blocker is fixed in [auto-deferred] |
Address-review summaryScan scope: full PR history through 2026-07-27T18:02:46Z; no previous address-review cutoff existed. Mattered
Optional
Skipped
Autonomously resolved threads
Deferred-work tracking: none; no follow-up issue is warranted for these optional refactors/comments. Next default scan starts after this comment. Say |
|
+ci-status |
|
+ci-run-hosted |
CI StatusHead SHA: Only the required gate is active unless hosted CI is requested. |
Hosted CI RequestedTriggered 9 workflow(s) for View progress in the Actions tab. |
Review SummaryI reviewed the caching-safety fix in Overall: solid, well-reasoned change. No functional bugs found. Highlights of what I verified:
Minor (non-blocking) observations
No security or performance concerns identified — this is a pure caching-correctness fix with no new user-input surface, and the added |
|
Current-head Claude review disposition for #4804 (comment):
|
|
@greptileai review |
Address-review summaryScan scope: review activity since the previous summary at 2026-07-27T18:03:05Z, on exact head Blocking findings: None. Optional:
Skipped:
Unresolved review threads: 0. Next default scan begins after this summary timestamp. |
…t-policy * origin/main: (33 commits) Fix ci-required base ref for PR merge-ref checkouts (#4819) Honor response charset and reject non-2xx HTTP-served SSR bundles (#4817) [Pro] Redact RSC render-error metadata on the fetched (client-navigation) payload path (#4821) Forward-port the 17.0.1 changelog section to main (#4814) Handle selector metacharacters in renderComponent DOM IDs (#4808) [Pro] Prevent caching RSC renders with errors (#4804) Agents: trust Copilot review identities (#4807) Agents: bind fleet closeout to generated pack (#4805) Docs: ADR 0002 — Skills-in-package over MCP for agent-native DX (#4735) Scope GitHub release commands to the origin repository (#4803) Forward-port OSS npm license metadata fix (#4794) Add golden-output gate for the serverWebpackConfig generator template (#4790) Cover the rspack CSS SSR generator fixes and de-duplicate the loader path (#4788) Configure agent workflow repo policy (#4785) Forward-port gh include mixed framing from #4684 (#4784) Release: enforce one-change forward-port closeout (#4783) Forward-port multi-URL rolling-deploy seeding to main (#4782) Docs: clarify React 18 streaming without RSC (#4780) Docs: forward-port v17 upgrade and generator gate guidance (#4781) Record the final React on Rails 17.0.0 changelog (#4742) ... # Conflicts: # AGENTS.md # internal/contributor-info/release-train-runbook.md
…ential-broker * origin/main: (75 commits) Silence routine startup diagnostics for Rails commands (#4849) Docs: move agent coordination to the HTTP backend (#4764) Detect unnoticed changes across generated webpack/Rspack configs (#4839) Fix durable ShakaPerf release evidence reuse (#4833) Docs: add missing content — release notes, upgrade guide, config, API references (#4843) (#4844) Fix incorrect docs: helper names, defaults, requirements, runtime refs (#4836) Scroll-priority streaming: candidate architecture evaluation (#4835) (#4841) Fix generated server config lint cleanup (#4840) Document serialized release backport policy (#4592) Package version-matched agent skills and docs (#4809) Fix ci-required base ref for PR merge-ref checkouts (#4819) Honor response charset and reject non-2xx HTTP-served SSR bundles (#4817) [Pro] Redact RSC render-error metadata on the fetched (client-navigation) payload path (#4821) Forward-port the 17.0.1 changelog section to main (#4814) Handle selector metacharacters in renderComponent DOM IDs (#4808) [Pro] Prevent caching RSC renders with errors (#4804) Agents: trust Copilot review identities (#4807) Agents: bind fleet closeout to generated pack (#4805) Docs: ADR 0002 — Skills-in-package over MCP for agent-native DX (#4735) Scope GitHub release commands to the origin repository (#4803) ...
Why
Buffered and static RSC helpers could persist an error-containing render in
Rails.cache, allowing a later request to receive that rejected output as a cache hit. This closes #4723 while preserving caching for clean renders.What changed
hasErrorsmetadata through both buffered and static RSC render paths.Rails.cache.fetchbefore its write step.nilcaching, andrace_condition_ttlbehavior.The cache-write bypass uses Ruby's uniquely scoped
catch/throwcontrol flow instead ofskip_nil, because React on Rails Pro still supports ActiveSupport versions whose cache implementation predatesskip_nil.Verification
skip_nil): rejected buffered/static renders were returned and no cache entry was written.nilbehavior is unchanged.git diff --check, Pro license-header audit, and commit hooks passed.codex review --base origin/main: no actionable findings.The broad helper spec currently has 23 unrelated failures because this checkout does not contain
react_on_rails_pro/spec/dummy/ssr-generated/server-bundle.js; focused tests that do not depend on that generated bundle pass.Churn and scope
This PR changes only the Pro helper, its focused dummy-app helper spec, and the changelog. No package, generator, or public API changes are included.
Fixes #4723
Summary by CodeRabbit
Bug Fixes
Tests
Documentation