Skip to content

[1.9] Fix ClassCastException when reading "stack" of an error with a changed prototype - #2544

Merged
gbrail merged 1 commit into
mozilla:rhino_1_9_backportsfrom
average-web-dev:rhino-1.9-backport-error-stack-cce
Oct 31, 2026
Merged

gbrail merged 1 commit into
mozilla:rhino_1_9_backportsfrom
average-web-dev:rhino-1.9-backport-error-stack-cce

Conversation

@average-web-dev

Copy link
Copy Markdown

On 1.9.2, reading stack of an error whose prototype was replaced throws a
Java ClassCastException, which scripts cannot catch:

function E() {}
E.prototype = Object.create(Error.prototype);
var e = new Error("m");
Object.setPrototypeOf(e, E.prototype);
e.stack; // java.lang.ClassCastException: NativeObject cannot be cast to NativeError

This is exactly what transpiled class MyError extends Error {} does (Babel's
wrapNativeSuper), so reading .stack of any transpiled custom error fails.

Cause and fix

NativeError.getStackDelegated() casts the error's prototype to NativeError
to look up the stack trace settings (stackTraceLimit, prepareStackTrace).
On master this cast was changed to ScriptableObject in #2295 ("Convert
NativeError to descriptor"), but that PR can't be backported on its own.

This PR only checks whether the prototype is a ScriptableObject and otherwise
uses the default settings. This also covers a null prototype and a Proxy as
prototype. A null prototype still throws a NullPointerException on
master; I can open a separate PR for that.

Tests

New test ErrorPropertiesTest.stackWithChangedPrototype for a plain object,
null and a Proxy as prototype, in all modes. It fails without the fix. The
full test suite passes, except NativeDateTest.toTimeStringEST, which also
fails on an unmodified rhino_1_9_backports on my machine (time zone data).
test262.properties doesn't change.

A note on how this was developed

I developed this PR with the help of an AI coding agent (Claude Code), and I
reviewed, tested and take responsibility for all of the changes. If the project
has concerns about or rules for AI-assisted contributions, please let me know.

I'm dyslexic, so I usually let AI help me write or proofread text like this
description. If anything reads unclear, please ask and I'll clarify.

🤖 Generated with Claude Code

…d prototype

NativeError.getStackDelegated() cast the error's prototype to NativeError to
look up the stack trace settings. If the prototype was replaced, for example by
Object.setPrototypeOf() as transpiled "class MyError extends Error" does, this
threw a Java ClassCastException, or a NullPointerException for a null
prototype. Fall back to the default settings instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gbrail

gbrail commented Oct 31, 2026

Copy link
Copy Markdown
Collaborator

Here, are you sure that this is a 1.9 bug or one in the master branch?

@average-web-dev

Copy link
Copy Markdown
Author

Partly both. The ClassCastException from the description is 1.9 only: on master, #2295 changed the cast to ScriptableObject. But with a null prototype, master still throws a Java NullPointerException that a script's try/catch can't catch:

var e = new Error("m");
Object.setPrototypeOf(e, null);
e.stack; // java.lang.NullPointerException in NativeError.getStackDelegated()

I'll open a PR for master with the same fix and tests first, and then update this PR to be a backport of it.

@average-web-dev

Copy link
Copy Markdown
Author

I opened #2550 with the fix for master. This PR is its backport: the same
fix (a plain instanceof check and cast instead of pattern matching, since 1.9
targets Java 11) and the same test. On 1.9 the test also covers the
ClassCastException case from the description.

@gbrail
gbrail merged commit 0ad61f3 into mozilla:rhino_1_9_backports Oct 31, 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.

2 participants