Skip to content

TypeError stack-trace output diverges from Node — Perry's 'Uncaught exception:' prefix + missing file:line header (regression from v0.5.702 #596) #616

@proggeramlug

Description

@proggeramlug

Summary

test_issue_462_nullish_property_access.ts and test_issue_510_primitive_method_typeerror.ts both diverge from Node's parity output not because Perry's behavior is wrong, but because Perry's uncaught-exception format doesn't match Node's. Both tests trigger a real TypeError and Perry correctly throws it; the test's UNREACHABLE line correctly never prints. The remaining failure is purely the framing.

This regressed in v0.5.702 (#596 — TypeError throw helpers route through js_throw). The print_uncaught function in crates/perry-runtime/src/exception.rs:159+ was modified at that point to emit a single Uncaught exception: <Name>: <message> line plus the stack string.

Diff (test_issue_462)

Node:
  about to throw — last line of stdout
  file:///Users/.../test_issue_462_nullish_property_access.ts:33
  console.log(undef.foo);
                    ^

  TypeError: Cannot read properties of undefined (reading 'foo')
      at file:///.../test_issue_462_nullish_property_access.ts:33:19
      at ModuleJob.run (node:internal/modules/esm/module_job:430:25)
      ...

Perry:
  about to throw — last line of stdout
  Uncaught exception: TypeError: Cannot read properties of undefined (reading 'foo')
  TypeError: Cannot read properties of undefined (reading 'foo')
      at <anonymous>

Three concrete differences:

  1. Perry has the Uncaught exception: prefix; Node does not.
  2. Perry omits the file:line "header" block (file URL, source-line, caret, blank).
  3. Stack frames differ — Perry's at <anonymous> vs Node's at <file>:<line>:<col> + module-job frames.

Symptom shared by

  • test_issue_462_nullish_property_access
  • test_issue_510_primitive_method_typeerror

(any future test that intentionally throws + lets it escape will hit the same format divergence)

Reproducer

const x: any = undefined;
console.log(x.foo);  // throws TypeError

node --experimental-strip-types repro.ts vs perry repro.ts && ./out produces the diff above.

Suggested approach

If matching Node byte-for-byte is the goal: extend print_uncaught in exception.rs to emit a Node-shaped header. Source-line + caret requires reading the original source text + columns, which the runtime doesn't currently retain at throw time — would need an HIR-side annotation that flows the source-text snippet for the throwing site to the runtime.

If matching Node exactly is unrealistic (Perry's stack frames have a different shape — no module-job, no async-job machinery), an alternative: keep the current Perry format but add it to the parity harness's known-divergence allowlist, so these tests don't show up as failures every sweep.

Environment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingparityNode.js compatibility / parity gaps

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions