RaiseError
Raises a runtime error, optionally skipping the current subscriber or returning an API error. Runtime-proven on a live Marketing Cloud Engagement CloudPage — including that outside a send it is not a graceful abort: the message never reaches the caller and the response is indistinguishable from any other failure.
Syntax
RaiseError(message[, skipSubscriber, apiErrorCode, apiErrorNumber, preserveDataExt]) → void
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
message |
string | Yes | Error message |
skipSubscriber |
string | boolean | number | No | Skip only the current subscriber and continue the job, rather than stopping it |
apiErrorCode |
string | No | Custom API error code |
apiErrorNumber |
number | No | Custom API error number |
preserveDataExt |
boolean | No | Retain data extension writes made before the error, even when the subscriber is skipped |
Example
%%[
VAR @code
SET @code = QueryParameter("code")
IF Empty(@code) THEN
RaiseError("No code supplied")
ENDIF
]%%
Renders nothing at all when the guard fires: the request ends with HTTP 422 and a fixed failure notice, and the supplied text appears nowhere in it.
The realistic pattern is to raise inside a send, where the second argument decides whether the job stops or only the current subscriber is skipped.
%%[
VAR @rows
SET @rows = LookupRows("Coupons", "Status", "free")
IF RowCount(@rows) == 0 THEN
RaiseError("No coupon left for this subscriber", true)
ENDIF
]%%
On a landing page that second argument changes nothing you can observe — see below.
Return value
void — nothing is returned. On a landing page the request is abandoned and the body is replaced by a fixed failure notice rather than the message you passed.
There is no closed set of sentinel values to test for; the function answers with an aborted request rather than a value.
Behaviour
It is not a graceful abort on a landing page. The request ends with HTTP 422 and the response body is a short fixed failure notice. That is the same status and the same body every other aborting AMPscript call produces.
Everything written before the call is discarded. Two marker lines written immediately before the call, the surrounding block’s own start marker, and even a control line written at the very top of the page — one that renders on every other request — were all missing from the response. Nothing that ran earlier reaches the browser.
Nothing after the call runs. The marker line placed after the call and the block’s closing marker were both absent.
The caller never sees the message. Four separate runs passed four distinct messages and none of them appeared anywhere in the response. Whatever you write there is for the send log, not for the visitor.
The second argument accepts three spellings interchangeably. Unquoted true, unquoted false, the numbers 1 and 0, and the quoted "true" were each run in isolation and all five produced the identical response. That is why the type is written as three alternatives rather than as a boolean.
Telling it apart from an unrelated failure
A control run in the same deployment aborted for a reason with nothing to do with this function — a wrong argument count on an unrelated string function. Its response was byte-for-byte the same: HTTP 422, same body length, same text.
| Run | Status | Body |
|---|---|---|
| A call to this function | 422 | fixed failure notice |
| An unrelated aborting call | 422 | the same fixed failure notice |
So from outside the page the two cannot be distinguished. If you need a visitor-facing error, render your own message and stop the flow with an IF branch instead — this function gives the caller nothing to read.
Show test script
%%[
VAR @b
SET @b = RequestParameter("b")
/* known-good control: renders on every request, so a run of HTTP 422s
can be told apart from a broken deploy */
OutputLine(Concat("CTRL=[", Uppercase("ok"), "]"))
OutputLine(Concat("GATE=[", @b, "]"))
/* the markers before and after the call are the point: NEITHER is
delivered, and neither is the control line above */
IF @b == "re1" THEN
OutputLine(Concat("--- re1 start ---"))
OutputLine(Concat("RE_BEFORE=[written-before]"))
RaiseError("probe-msg-one")
OutputLine(Concat("RE_AFTER=[written-after]"))
OutputLine(Concat("--- re1 done ---"))
ENDIF
/* all three spellings of the flag are accepted and all reach the same
abort, so the parameter is not boolean-only */
IF @b == "re2t" THEN
OutputLine(Concat("--- re2t start ---"))
RaiseError("probe-msg-two-true", true)
OutputLine(Concat("--- re2t done ---"))
ENDIF
IF @b == "re2f" THEN
OutputLine(Concat("--- re2f start ---"))
RaiseError("probe-msg-two-false", false)
OutputLine(Concat("--- re2f done ---"))
ENDIF
IF @b == "re2n1" THEN
OutputLine(Concat("--- re2n1 start ---"))
RaiseError("probe-msg-num-one", 1)
OutputLine(Concat("--- re2n1 done ---"))
ENDIF
IF @b == "re2n0" THEN
OutputLine(Concat("--- re2n0 start ---"))
RaiseError("probe-msg-num-zero", 0)
OutputLine(Concat("--- re2n0 done ---"))
ENDIF
IF @b == "re2q" THEN
OutputLine(Concat("--- re2q start ---"))
RaiseError("probe-msg-quoted-true", "true")
OutputLine(Concat("--- re2q done ---"))
ENDIF
IF @b == "re5" THEN
OutputLine(Concat("--- re5 start ---"))
RaiseError("probe-msg-five", true, "PROBECODE", 4321, true)
OutputLine(Concat("--- re5 done ---"))
ENDIF
IF @b == "re0" THEN
OutputLine(Concat("RE0_START=[x]"))
RaiseError()
OutputLine(Concat("RE0_DONE=[x]"))
ENDIF
IF @b == "re6" THEN
OutputLine(Concat("RE6_START=[x]"))
RaiseError("probe-msg-six", true, "PROBECODE", 4321, true, "extra")
OutputLine(Concat("RE6_DONE=[x]"))
ENDIF
/* the control gate: it aborts for a reason that has nothing to do with
this function, yet the caller sees exactly the same response */
IF @b == "ctlabort" THEN
OutputLine(Concat("CTL_START=[x]"))
OutputLine(Concat("CTL=[", Uppercase(), "]"))
OutputLine(Concat("CTL_DONE=[x]"))
ENDIF
]%%
What a page cannot show is the documented purpose: stopping an email job, skipping a single subscriber while the job continues, and the fate of the API error code and number. All of those are properties of a send and were not exercised here. The official reference describes only send behaviour and makes no landing-page claim, so the abort above is undocumented territory rather than a contradiction.
Availability
| Platform | Available |
|---|---|
| Marketing Cloud Engagement | Yes |
| Marketing Cloud Next | Yes, from API 67.0 |
See also
- Redirect — the other page-terminating Utility function, which ends the request with a 302 instead
- Official reference · ampscript.guide