Error()
→ objectNative JavaScript Error constructor for creating throwable error objects in try/catch error handling.
Syntax
new Error([message])
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
message |
string | No | Human-readable description of the error. After new Error(msg) it is not readable via .message (use String(e)). After call-form Error(msg) or on engine-raised errors, .message is set. |
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");
/*
* Chapter: Parameters — the optional `message` argument
*
* Proves:
* 1. Error accepts 0 or 1 arguments; both forms return an object.
* 2. After new Error(msg) the text is NOT readable via .message —
* it is undefined and not an own property (MDN: .message === msg).
* 3. The documented recovery: String(e) and ("" + e) return the text.
* 4. After call-form Error(msg) the .message IS set, and it is an own
* property.
* 5. Engine-raised errors also carry .message.
* 6. With no argument: new Error() leaves .message undefined, while
* call-form Error() still sets it — to the empty string.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
var got;
try { got = String(actual); } catch (ex) { got = "THREW"; }
Platform.Response.Write((got === String(expected) ? "PASS " : "FAIL ") + id + " -> [" + got + "]\n");
}
/* 1. Arity — 0 and 1 argument both produce an object. */
var noArg = new Error();
assert("typeof new Error() is object", typeof noArg, "object");
var oneArg = new Error("boom");
assert("typeof new Error('boom') is object", typeof oneArg, "object");
var callNoArg = Error();
assert("typeof Error() call-form is object", typeof callNoArg, "object");
/* 2. DEVIATION — new Error(msg) does not populate .message. */
assert("DEV typeof new Error('boom').message is undefined (MDN: 'boom')", typeof oneArg.message, "undefined");
assert("DEV new Error('boom').hasOwnProperty('message') is false (MDN: true)", oneArg.hasOwnProperty("message"), "false");
/* 3. Documented recovery of the text. */
assert("workaround String(new Error('boom')) is 'boom'", String(oneArg), "boom");
assert("workaround ('' + new Error('boom')) is 'boom'", "" + oneArg, "boom");
/* 4. Call-form DOES set .message. */
var callForm = Error("via-call");
assert("Error('via-call').message is 'via-call'", callForm.message, "via-call");
assert("Error('via-call').hasOwnProperty('message') is true", callForm.hasOwnProperty("message"), "true");
assert("String(Error('via-call')) is 'via-call'", String(callForm), "via-call");
/* 5. Engine-raised errors carry .message. */
var engineMsgType = "not-thrown";
try {
Platform.Function.Lookup("NonExistentDE_ForTest", "Field", "Key", "value");
} catch (ex) {
engineMsgType = typeof ex.message;
}
assert("engine-raised error exposes a string .message", engineMsgType, "string");
/* 6. No-argument forms leave .message undefined. */
assert("typeof new Error().message is undefined", typeof noArg.message, "undefined");
/* Call-form always sets .message; with no argument it is the empty string. */
assert("Error() call-form sets .message to the empty string", callNoArg.message, "");
assert("Error() call-form .message is a string", typeof callNoArg.message, "string");
</script>
Description
Error is the native JavaScript Error constructor. Use it with throw and try/catch for structured error handling in SSJS.
Unlike standard JavaScript, new Error("msg") in the SFMC (Jint) engine does not populate .message — it reads back undefined (not an own property). Recover the text with String(e) or ("" + e). Call-form Error("msg") does set .message, and engine-raised errors set both .message and .description. e.toString() after new Error("msg") returns "Error: undefined". instanceof Error is always false; for JS-constructed errors use e.constructor === Error or e.name.
Show test script — message shape, toString and instanceof deviations
<script runat="server">
Platform.Load("core", "1.1.5");
/*
* Chapter: Description + differs-from-MDN callout
*
* MDN / ECMAScript says:
* - new Error("msg").message === "msg"
* - new Error("msg").toString() === "Error: msg"
* - (new Error()) instanceof Error === true
*
* SFMC (Jint) actually does:
* 1. new Error("msg") leaves .message undefined — recover with String(e)
* or ("" + e).
* 2. Call-form Error("msg") DOES set .message.
* 3. Engine-raised errors set BOTH .message and .description.
* 4. e.toString() after new Error("msg") returns "Error: undefined".
* 5. instanceof Error is always false — use e.constructor === Error
* or e.name instead.
*
* Also proves the base shape: Error is a function, .name is "Error",
* and the object is throwable/catchable.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
var got;
try { got = String(actual); } catch (ex) { got = "THREW"; }
Platform.Response.Write((got === String(expected) ? "PASS " : "FAIL ") + id + " -> [" + got + "]\n");
}
/* 0. Base shape. */
assert("typeof Error is function", typeof Error, "function");
var e = new Error("msg");
assert("new Error('msg').name is 'Error'", e.name, "Error");
/* 1. DEVIATION — .message is not populated by the new-form. */
assert("DEV typeof new Error('msg').message is undefined (MDN: 'msg')", typeof e.message, "undefined");
assert("DEV new Error('msg').hasOwnProperty('message') is false (MDN: true)", e.hasOwnProperty("message"), "false");
assert("workaround String(e) is 'msg'", String(e), "msg");
assert("workaround ('' + e) is 'msg'", "" + e, "msg");
/* 2. Call-form does set .message. */
var c = Error("msg2");
assert("Error('msg2').message is 'msg2'", c.message, "msg2");
/* 3. Engine-raised errors carry .message AND .description. */
var engMsg = "none", engDesc = "none";
try {
Platform.Function.Lookup("NonExistentDE_ForTest", "Field", "Key", "value");
} catch (ex) {
engMsg = typeof ex.message;
engDesc = typeof ex.description;
}
assert("engine-raised error .message is a string", engMsg, "string");
assert("engine-raised error .description is a string", engDesc, "string");
/* 4. DEVIATION — toString() after new loses the message. */
assert("DEV new Error('msg').toString() is 'Error: undefined' (MDN: 'Error: msg')", e.toString(), "Error: undefined");
assert("Error('msg2').toString() is 'Error: msg2'", c.toString(), "Error: msg2");
/* 5. DEVIATION — instanceof Error is always false. */
assert("DEV new Error('msg') instanceof Error is false (MDN: true)", e instanceof Error, "false");
assert("DEV Error('msg2') instanceof Error is false (MDN: true)", c instanceof Error, "false");
assert("workaround e.constructor === Error is true", e.constructor === Error, "true");
assert("workaround e.name is 'Error'", e.name, "Error");
/* 6. instanceof stays false even after throw/catch. */
var caughtInstance = "not-run", caughtName = "not-run";
try {
throw new Error("thrown");
} catch (ex) {
caughtInstance = ex instanceof Error;
caughtName = ex.name;
}
assert("DEV caught new Error instanceof Error is false (MDN: true)", caughtInstance, "false");
assert("caught new Error .name is 'Error'", caughtName, "Error");
</script>
Examples
Basic throw and catch
try {
throw new Error("Something went wrong");
} catch (e) {
// e.message is undefined after new Error — use String(e).
Write(String(e)); // "Something went wrong"
}
Call-form vs new (message shape)
var withNew = new Error("via-new");
Write(withNew.message); // undefined
Write(String(withNew)); // "via-new"
var callForm = Error("via-call");
Write(callForm.message); // "via-call"
Write(String(callForm)); // "via-call"
Conditional error
function getSubscriberEmail(sk) {
if (!sk) {
throw new Error("SubscriberKey is required");
}
// String() first — a Lookup result throws on a truthiness test when the field is empty
var email = String(Platform.Function.Lookup("Subscribers", "Email", "SubscriberKey", sk));
if (email === "" || email === "null") {
throw new Error("No subscriber found for key: " + sk);
}
return email;
}
try {
var email = getSubscriberEmail(subscriberKey);
Write("<p>Email: " + email + "</p>");
} catch (e) {
// String(e) recovers the thrown message; e.message would be undefined here.
Write('<p class="error">' + String(e) + "</p>");
}
HTTP error handling
try {
var req = new Script.Util.HttpRequest("https://api.example.com/data");
req.method = "GET";
req.continueOnError = true;
var resp = req.send();
// statusCode is a CLR value — Number() converts it so === works
var status = Number(resp.statusCode);
if (status === 401) {
throw new Error("Unauthorized: check your access token");
} else if (status !== 200) {
throw new Error("API returned status " + status);
}
var data = Platform.Function.ParseJSON(String(resp.content) + "");
// process data...
} catch (e) {
// Use String(e) — e.message is undefined for new Error(...).
Platform.Function.InsertData("ErrorLog", "Message", String(e), "Timestamp", Platform.Function.Now());
Platform.Response.Redirect("/error", false);
}
Error in serialization
Stringify(e) behaves differently depending on how the error was created:
- For
new Error(...),Stringify(e)is often{}when not thrown, or surfaces a hidden{"jintException": ...}afterthrow/catch— not the message. UseString(e)to log the message. - For call-form
Error("msg"),Stringify(e)yields{"message":"msg"}. - For an engine-raised error,
Stringify(e)yields{"message": ..., "description": ...}.
try {
performOperation();
} catch (e) {
// For engine-raised errors this includes message + description;
// for new Error(...) prefer String(e) to capture the message.
Write("<pre>Error details: " + String(e) + " | " + Stringify(e) + "</pre>");
}
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");
/*
* Chapter: Examples
*
* Proves every commented result in the chapter's example blocks:
* 1. Basic throw/catch — String(e) is "Something went wrong".
* 2. Call-form vs new:
* new Error("via-new").message -> undefined
* String(new Error("via-new")) -> "via-new"
* Error("via-call").message -> "via-call"
* String(Error("via-call")) -> "via-call"
* 3. Conditional error — a guard clause throws and the catch recovers the
* message text via String(e).
* 4. Error in serialization:
* Stringify(new Error(...)) not thrown -> "{}" (NOT the message)
* Stringify(Error("msg")) -> {"message":"msg"}
* Stringify(engine-raised) -> contains message + description
* Stringify of a CAUGHT new Error -> does not contain the message
*
* The HTTP example is illustrative only (live HTTP calls time a CloudPage
* out); its throw/catch shape is covered by points 1 and 3.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
var got;
try { got = String(actual); } catch (ex) { got = "THREW"; }
Platform.Response.Write((got === String(expected) ? "PASS " : "FAIL ") + id + " -> [" + got + "]\n");
}
function assertThrows(id, fn) {
var threw = false;
try { fn(); } catch (ex) { threw = true; }
Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw" : "did NOT throw") + "\n");
}
/* 1. Basic throw and catch. */
var basic = "not-run";
try {
throw new Error("Something went wrong");
} catch (ex) {
basic = String(ex);
}
assert("String(e) after throw new Error is 'Something went wrong'", basic, "Something went wrong");
/* 2. Call-form vs new. */
var withNew = new Error("via-new");
assert("new Error('via-new').message is undefined", typeof withNew.message, "undefined");
assert("String(new Error('via-new')) is 'via-new'", String(withNew), "via-new");
var callForm = Error("via-call");
assert("Error('via-call').message is 'via-call'", callForm.message, "via-call");
assert("String(Error('via-call')) is 'via-call'", String(callForm), "via-call");
/* 3. Conditional error — guard clause. */
function getValue(sk) {
if (!sk) {
throw new Error("SubscriberKey is required");
}
return sk;
}
assertThrows("guard clause throws when the argument is missing", function () { return getValue(""); });
var guardText = "not-run";
try {
getValue("");
} catch (ex) {
guardText = String(ex);
}
assert("caught guard message is 'SubscriberKey is required'", guardText, "SubscriberKey is required");
assert("guard returns the value when present", getValue("abc"), "abc");
/* 4. Error in serialization. */
var notThrown = new Error("serialize-me");
assert("Stringify(new Error(...)) not thrown is '{}'", Stringify(notThrown), "{}");
var callErr = Error("msg");
assert("Stringify(Error('msg')) is the message object", Stringify(callErr), '{"message":"msg"}');
var caughtDump = "not-run";
try {
throw new Error("hidden-text");
} catch (ex) {
caughtDump = Stringify(ex);
}
assert("Stringify of a caught new Error does NOT contain the message", caughtDump.indexOf("hidden-text") === -1, "true");
var engDump = "not-run";
try {
Platform.Function.Lookup("NonExistentDE_ForTest", "Field", "Key", "value");
} catch (ex) {
engDump = Stringify(ex);
}
assert("Stringify(engine-raised) contains 'message'", engDump.indexOf("message") > -1, "true");
assert("Stringify(engine-raised) contains 'description'", engDump.indexOf("description") > -1, "true");
</script>
Notes
The error object in SSJS is similar to but not identical to the standard ECMAScript Error object, and its shape depends on origin:
new Error("msg"):.messageisundefined(not own); recover viaString(e)/("" + e)..nameis"Error"..stackis unavailable.instanceof Errorisfalse;e.constructor === Erroristrue.- Call-form
Error("msg"):.messageis set to the argument;hasOwnProperty("message")istrue;toString()returns"Error: msg". - Engine-raised (platform-thrown, e.g. a bad
Platform.Functioncall): exposes.message(short) and.description(fuller text)..stackis unavailable.instanceof Error/instanceof TypeErrorare stillfalse. - Thrown primitives / plain objects (
throw "text",throw { message: ..., description: ... }) are valid; incatch (e),emay be a string, a plain object, or an engine error — probe accordingly. AvoidString(e)on a thrown plain object (it can throw a .NET null-reference); preferStringify(e)ore.toString()there. for (var k in e)is unreliable for property discovery: on engine errors, JSErrorinstances, and thrown strings it enumerates the message characters, not property names.
SFMC platform errors (not thrown by your code) are also catchable, and these DO carry .message:
try {
Platform.Function.Lookup("NonExistentDE", "Field", "Key", "value");
} catch (e) {
// Engine-raised errors expose .message and .description.
Write("Platform error: " + e.message);
}
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");
/*
* Chapter: Notes — the error object's shape depends on its origin
*
* Proves, per origin:
* 1. new Error("msg"): .message undefined (not own), recover via String(e)
* / ("" + e); .name is "Error"; .stack unavailable;
* instanceof Error is false; e.constructor === Error is true.
* 2. Call-form Error("msg"): .message set, hasOwnProperty("message") true,
* toString() is "Error: msg".
* 3. Engine-raised: .message (short) + .description (fuller); .stack
* unavailable; instanceof Error and instanceof TypeError both false.
* 4. Thrown primitives / plain objects are valid — catch receives a string
* or a plain object; on a thrown plain object prefer Stringify(e) /
* e.toString() over String(e).
* 5. for (var k in e) enumerates the message CHARACTERS, not property
* names, for engine errors / JS Error instances / thrown strings.
* 6. SFMC platform errors are catchable and DO carry .message.
*
* All "DEV" lines name the MDN/spec expectation inline.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
var got;
try { got = String(actual); } catch (ex) { got = "THREW"; }
Platform.Response.Write((got === String(expected) ? "PASS " : "FAIL ") + id + " -> [" + got + "]\n");
}
/* 1. new Error("msg"). */
var e = new Error("msg");
assert("DEV new Error('msg').message is undefined (MDN: 'msg')", typeof e.message, "undefined");
assert("DEV new Error('msg') has no own 'message' (MDN: own property)", e.hasOwnProperty("message"), "false");
assert("String(new Error('msg')) recovers the text", String(e), "msg");
assert("('' + new Error('msg')) recovers the text", "" + e, "msg");
assert("new Error('msg').name is 'Error'", e.name, "Error");
assert("DEV new Error('msg').stack is unavailable (MDN: a string)", typeof e.stack, "undefined");
assert("DEV new Error('msg') instanceof Error is false (MDN: true)", e instanceof Error, "false");
assert("new Error('msg').constructor === Error is true", e.constructor === Error, "true");
/* 2. Call-form Error("msg"). */
var c = Error("msg");
assert("Error('msg').message is 'msg'", c.message, "msg");
assert("Error('msg').hasOwnProperty('message') is true", c.hasOwnProperty("message"), "true");
assert("Error('msg').toString() is 'Error: msg'", c.toString(), "Error: msg");
/* 3. Engine-raised error. */
var engMsgType = "none", engDescType = "none", engStack = "none";
var engIsError = "none", engIsTypeError = "none";
try {
Platform.Function.Lookup("NonExistentDE_ForTest", "Field", "Key", "value");
} catch (ex) {
engMsgType = typeof ex.message;
engDescType = typeof ex.description;
engStack = typeof ex.stack;
engIsError = ex instanceof Error;
engIsTypeError = ex instanceof TypeError;
}
assert("engine-raised .message is a string", engMsgType, "string");
assert("engine-raised .description is a string", engDescType, "string");
assert("DEV engine-raised .stack is unavailable (MDN: a string)", engStack, "undefined");
assert("DEV engine-raised instanceof Error is false (MDN: true)", engIsError, "false");
assert("DEV engine-raised instanceof TypeError is false", engIsTypeError, "false");
/* 4. Thrown primitives and plain objects. */
var thrownStr = "not-run", thrownStrType = "not-run";
try {
throw "plain text";
} catch (ex) {
thrownStrType = typeof ex;
thrownStr = String(ex);
}
assert("throw 'text' is catchable and typeof e is string", thrownStrType, "string");
assert("caught thrown string equals the thrown text", thrownStr, "plain text");
var objType = "not-run", objMsg = "not-run", objDump = "not-run";
try {
throw { message: "obj-msg", description: "obj-desc" };
} catch (ex) {
objType = typeof ex;
objMsg = ex.message;
objDump = Stringify(ex);
}
assert("throw {plain object} is catchable and typeof e is object", objType, "object");
assert("caught plain object keeps .message", objMsg, "obj-msg");
assert("Stringify(thrown plain object) contains the description", objDump.indexOf("obj-desc") > -1, "true");
/* 5. for..in enumerates the message CHARACTERS, not property names. */
var keys = [];
for (var k in e) { keys.push(k); }
assert("DEV for..in over a JS Error yields characters, not property names", keys.join(""), "msg");
assert("DEV for..in key count equals the message length, not 1", keys.length, 3);
var strKeys = [];
var thrownText = "";
try { throw "abcd"; } catch (ex) { thrownText = ex; for (var k2 in ex) { strKeys.push(k2); } }
assert("DEV for..in over a thrown string yields its characters", strKeys.join(""), "abcd");
/* 6. SFMC platform errors are catchable and expose .message. */
var platMsg = "not-run";
try {
Platform.Function.Lookup("NonExistentDE_ForTest", "Field", "Key", "value");
} catch (ex) {
platMsg = ex.message;
}
assert("platform error .message is a non-empty string", platMsg.length > 0, "true");
</script>