Skip to content

Error stack traces have no frames: 'at <anonymous>' where node prints the real call chain — kills cc doctor output and commander error rendering #9486

Description

@proggeramlug

From the 196-case cc stress re-run (main+#9479). Two spellings of one gap:

cc doctor (B01/B02, and B62 setup-token): ink's raw-mode error renders err.stack. Node prints ten real frames; perry prints one placeholder:

node : - handleSetRawMode (file://<CLI>:574:5473)
       -  (file://<CLI>:601:4834)
       - S0 (file://<CLI>:551:63170)
       … (10 frames)
perry: -     at <anonymous>

commander's parse error (C24, --max-budget-usd abc): node prints the source excerpt, code frame, message and stack (14,573 bytes of stderr); perry prints 120 bytes — the bare message. E30_corrupt_config_mcp_list's 885-vs-1024-byte stderr diff is likely the same family (verify before assuming).

Why this matters beyond parity

Stack traces are how everything else gets debugged. Every divergence investigation in this campaign that touched cc had to work around frameless errors — the #9417 hunt needed gdb + a symbolized build precisely because a JS-level stack said <anonymous>.

Relation to existing work

#9432/#9410 added .stack existence for Error subclasses (a frame captured at construction, name: message head formatted on read). This issue is about frame content: the capture produces no usable frames for ordinary throws on real call stacks. #9468 (method source text) is adjacent but separate — frames need function names and positions, not source text.

Perry compiles to native, so JS-frame names/positions need either the existing symbolication tables (the PERRY_KEEP_SYMBOLS path proves names exist) wired into the stack captor, or a side table mapping return addresses → function display names. Scope the cost before building: cc-sized binaries have 141k functions; the doctor case only needs names+offsets, not columns.

Verification bar

A fixture comparing new Error().stack shape (frame count > 1, function names present) for: a plain function chain, a method call, an async function, a class constructor, and a callback through a builtin (arr.map(fn)) — byte-comparing against node is NOT the bar here (positions will differ legitimately); assert structure. Plus the cc-level check: doctor's stderr frame count.

Cases: B01, B02, B62, C24 (+E30 to verify) of the stress suite — /root/claude-ccstress/report_detail.txt.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions