Better Formatting of Ampscript and SSJS Error Messages on CloudPages


When building various solutions on CloudPages like consent management centers, surveys or tools used be internal teams, you might run into errors during the development phase.

Here’s a code snippet for you if you don’t like feeling like trying to find a needle in the haystack of code that could land in the output of an error message.


Avoiding Error 500

You probably know you can use SSJS to wrap the code and avoid the dreaded Error 500…

If you don’t remember it, here’s a refresher – you just wrap your code in SSJS and use the try...catch function there – it will let you know what was wrong.

<script runat="server">
Platform.Load("core","1.1.5");
    try{
</script>%%=contentBlockByKey("test-force-error-snippet")=%%<script runat="server">
    }catch(error){
        Write(Stringify(error))
    }
</script>

Let me give you an example of a forced error with this snippet which I will later wrap in the SSJS:

%%[
set @sampleText = ''
set @textIndex = IndexOf(@sampleText)
]%%

This code will live in a code snippet with the following Customer Key: test-force-error-snippet. Here’s how the code would look like

<script runat="server">
Platform.Load("core","1.1.5");
    try{
</script>%%=contentBlockByKey("test-force-error-snippet")=%%<script runat="server">
    }catch(error){
        Write(Stringify(error))
    }
</script>

Here’s the resulting error message on a CloudPage

This haystack is not as big, so you will be able to fairly quickly identify this error message (the second highlighted selection in the image):

The function call does not include the minimum number of parameters required for the function\r\n Function Call: IndexOf(@sampleText)\r\n Function Name: IndexOf\r\n Number of Required Parameters: 2\r\n Number of Parameters in Call: 1

If this was a robust solution with much more code, you would need to ignore much more of the code included in the message (first selection in the image).

I was squinting at code for years, but then started to wonder if we couldn’t just do better. This lead me to on a short detour leading to…

Formatting the try… catch output

I ended with this function that can extend our try…catch block:

function formatTryCatchError(error){
    var errorMessage = Stringify(error);
        errorMessage = errorMessage.replace(/\\r\\n/g, '<br>').replace(/\r\n/g, '<br>').replace(/\\n/g, '<br>').replace(/\\n/g, '<br>').replace(/--- inner exception/g, '!@#$%^&* Inner Exception').replace(/---/g, '').replace(/- from Jint -->/g, '');
    var errorArray = errorMessage.split("!@#$%^&*");

    var errorColors = ["lightcoral", "lightsalmon", "lightpink", "yellow", "orange", "darkorange", "salmon", "darksalmon", "palevioletred" ];
    var colorIndex = Math.ceil(errorColors.length * Math.random());

    var errorMessageHTML = "<div style='font-family: monospace'>";
    errorMessageHTML += "<div style='font-family: monospace; border: 1px solid lightgrey; padding: 12px; margin: 12px;'><h3>Error Context</h3>";
    errorMessageHTML += "Current SFMC Server Time: " + Now();
    errorMessageHTML += "<br>Current MID: " + Platform.Recipient.GetAttributeValue('memberid') + "</div>";

    errorMessageHTML += "<div style='font-family: monospace; border: 1px solid lightgrey; padding: 12px; margin: 12px;'><h3>Error List:</h3>";

    if (errorArray.length > 1){

        for (errorIndex in errorArray){
            var thisError = errorArray[errorIndex];
            if (thisError.indexOf('Script:') > -1){
                thisError = thisError.substring(0, thisError.indexOf('Script:')); 
            } else if (thisError.length > 400){
                thisError = thisError.substring(0, 400) + "...";
            };
            
            if (errorIndex == errorArray.length - 1){
                thisError = thisError.replace('<br><br><br><br><br>\"}', '');
                errorMessageHTML += "<div style='font-family: monospace; background-color: " + errorColors[colorIndex] + "; padding: 12px; margin: 12px;'>" + thisError + "</div>";
            } else {
                errorMessageHTML += "<div style='font-family: monospace; border: 1px solid " + errorColors[colorIndex] + "; padding: 12px; margin: 12px;'>" + thisError + "</div>";
            }
        }
        
    } else {
        errorMessageHTML += errorMessage
    }
    errorMessageHTML += "</div></div>";
    return errorMessageHTML;
}

Example result from our failing code snippet:

The script selects a random color from the following palette:

var errorColors = ["lightcoral", "lightsalmon", "lightpink", "yellow", "orange", "darkorange", "salmon", "darksalmon", "palevioletred" ];

This and the inclusion of the current SFMC server time are there to make each reload of the page where the error occurs a little bit different, so that you know you are not looking at the same error output and the reload has finished.