Skip to content

Error.prototype.toString is undefined (ES2026 §20.5.3.4 missing) #545

@frostney

Description

@frostney

Engine bug: Error.prototype.toString is missing across the entire Error hierarchy

ES2026 §20.5.3.4 defines Error.prototype.toString as a method returning name + ": " + message (with edge cases for empty name/message). It is inherited by all native Error subclasses and by user class extends Error. In Goccia it is undefined everywhere.

Reproduce

./build.pas loader
cat > /tmp/probe.js <<'EOJS'
const e = new Error("hi");
console.log("typeof e.toString:", typeof e.toString);                    // expected "function", actual "undefined"
console.log("typeof Error.prototype.toString:", typeof Error.prototype.toString);

const t = new TypeError("nope");
console.log("typeof t.toString:", typeof t.toString);                    // expected "function", actual "undefined"

class MyErr extends Error {}
const m = new MyErr("custom");
console.log("typeof m.toString:", typeof m.toString);                    // expected "function", actual "undefined"

// Spec-correct String(error) result:
console.log("String(e):", String(e));                                    // expected "Error: hi"
EOJS
./build/GocciaScriptLoader /tmp/probe.js
./build/GocciaScriptLoader --mode=bytecode /tmp/probe.js

Both modes print undefined for all four typeof checks. String(e) post-#527 throws TypeError: Cannot convert object to primitive value because ToPrimitive(string) falls through to valueOf/toString and finds neither.

Spec context

ES2026 §20.5.3.4 Error.prototype.toString:

1. Let O be the this value.
2. If O is not an Object, throw a TypeError exception.
3. Let name be ? Get(O, "name").
4. If name is undefined, set name to "Error"; otherwise set name to ? ToString(name).
5. Let msg be ? Get(O, "message").
6. If msg is undefined, set msg to ""; otherwise set msg to ? ToString(msg).
7. If name is the empty String, return msg.
8. If msg is the empty String, return name.
9. Return the string-concatenation of name, ": ", and msg.

Defined on Error.prototype only — all NativeError subclasses inherit it through their prototype chain.

Likely fix area

source/units/Goccia.Builtins.Globals.pas — when FErrorProto is initialized (around the PROP_MESSAGE/PROP_NAME defines), also define PROP_TO_STRING as a method that runs the §20.5.3.4 algorithm. The other Error subclass prototypes (FTypeErrorProto, FRangeErrorProto, etc.) inherit from FErrorProto, so the method becomes available everywhere via the prototype chain — no per-subclass duplication.

Tests

Add to tests/built-ins/Error/prototype/ (or create toString.js if not present):

test("Error.prototype.toString returns name: message", () => {
  expect(new Error("hi").toString()).toBe("Error: hi");
});
test("TypeError.prototype.toString returns name: message", () => {
  expect(new TypeError("nope").toString()).toBe("TypeError: nope");
});
test("Error.prototype.toString returns just name when message is empty", () => {
  expect(new Error().toString()).toBe("Error");
  expect(new Error("").toString()).toBe("Error");
});
test("Error.prototype.toString returns just message when name is empty", () => {
  const e = new Error("foo");
  e.name = "";
  expect(e.toString()).toBe("foo");
});
test("user class extending Error inherits prototype.toString", () => {
  class MyErr extends Error {}
  expect(new MyErr("x").toString()).toBe("Error: x");
});
test("String(error) uses prototype.toString", () => {
  expect(String(new Error("hi"))).toBe("Error: hi");
});

User impact

Surfaced by

#527 (ES2026 ToStringLiteral refactor) — the spec ToString path now actually invokes obj.toString(), which is undefined for Error instances.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    engineTGocciaEngine: language semantics, ECMAScript built-ins, parser, interpreter, bytecode VMspec complianceMismatch against official JavaScript/TypeScript specification

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions