Skip to content

fix: Next.js standalone walls 46+47 — inherited-capture clobber + defineProperty on handle#5178

Merged
proggeramlug merged 1 commit into
mainfrom
feat/nextjs-wall-46
Jun 15, 2026
Merged

fix: Next.js standalone walls 46+47 — inherited-capture clobber + defineProperty on handle#5178
proggeramlug merged 1 commit into
mainfrom
feat/nextjs-wall-46

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

What

class NextNodeServer extends _baseserver.default (interop-ESM dynamic parent) read base-server's relative-require captures (_iserror/_utils/_logthis.__perry_cap_*) as undefined from inherited methods → Cannot read properties of undefined (reading 'getProperError') on every request (HTTP 500).

Root cause

Pinned via JS read-back probes at three points on the same instance and same method path:

  • parent-ctor end: captures = real objects ✓
  • post-construct (after new NextNodeServer() returns): undefined
  • request: undefined

So captures were written correctly by super() but clobbered during the derived class's own construction, after super() returned — the derived field-initializer phase. Synthesized capture fields (__perry_cap_*) are declared init: None, and apply_field_initializers_recursive emits this.<field> = undefined for every init: None field. When the field-init chain included the inherited dynamic parent's fields, that undefined-write re-initialized the captures super() had just populated. (ES runs derived field initializers after super(), so the clobber wins.)

Fix

Skip __perry_cap_* fields in the field-initializer loop (crates/perry-codegen/src/lower_call/new.rs). These synthesized fields are populated exclusively by the constructor's capture-param assignments, so a field-init undefined-write to them is always wrong.

Verification

Real Next.js standalone server: all captures resolve (_iserror/_utils/_log = object), getProperError TypeError gone. The request now reaches a deeper render error (separate wall). Continues the Next.js bring-up (#793; after #5152).

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Fixed an issue where certain initialization values were being incorrectly overwritten during constructor operations for inherited methods, ensuring values are properly preserved.

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 79baede4-be9c-42d3-a8db-5beeef326922

📥 Commits

Reviewing files that changed from the base of the PR and between 31e196e and 61cb262.

📒 Files selected for processing (1)
  • crates/perry-codegen/src/lower_call/new.rs

📝 Walkthrough

Walkthrough

In apply_field_initializers_recursive, a guard is added to skip synthesized capture fields (those with names prefixed __perry_cap_) when they are string-keyed (key_expr.is_none()). This prevents the derived/post-super() field-initializer pass from overwriting values already assigned via constructor capture parameters.

Changes

Capture Field Initializer Guard

Layer / File(s) Summary
Skip __perry_cap_* in apply_field_initializers_recursive
crates/perry-codegen/src/lower_call/new.rs
Adds an early continue in the per-field initializer loop: when a field is string-keyed and its name starts with __perry_cap_, the loop skips it to avoid overwriting the capture-param value already assigned during construction.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Poem

🐇 A capture once written, should never be lost,
So I hop past the field init loop at all cost.
__perry_cap_ fields, I skip with a bound,
No clobbering values that super has found.
The derived class is safe — onward I go! 🌿

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is comprehensive and addresses most template sections (What, Root cause, Fix, Verification), but does NOT follow the required template structure with Summary, Changes, Related issue, and Test plan sections as specified in CONTRIBUTING. Restructure the description to follow the template format: add explicit Summary and Changes sections, clarify Related issue status, and document the test plan with checkboxes.
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 (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main fix: preventing derived class field initialization from overwriting inherited capture fields in the Next.js standalone server scenario.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/nextjs-wall-46

Comment @coderabbitai help to get the list of available commands and usage tips.

…d captures

class X extends _mod.default read the parent's relative-require captures
(this.__perry_cap_*) as undefined from inherited methods. The captures were
correct after super() but clobbered during the DERIVED class's post-super
field-init phase: __perry_cap_* fields have init:None, so
apply_field_initializers_recursive emitted this.field=undefined for them,
re-initializing the inherited caps super() had just filled.

FIX: skip __perry_cap_* in the field-initializer loop — they are populated
exclusively by the ctor capture-param assignments, so a field-init
undefined-write is always wrong.
@proggeramlug proggeramlug force-pushed the feat/nextjs-wall-46 branch from 31e196e to 61cb262 Compare June 15, 2026 07:51
@proggeramlug proggeramlug merged commit 13dbae6 into main Jun 15, 2026
14 of 15 checks passed
@proggeramlug proggeramlug deleted the feat/nextjs-wall-46 branch June 15, 2026 07:51
@proggeramlug proggeramlug changed the title fix(codegen): Next.js wall 46 — derived field-init clobbered inherited captures fix: Next.js standalone walls 46+47 — inherited-capture clobber + defineProperty on handle Jun 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant