Throw error in API action step does not return the error in catch

Wappler Version : 7B16
Operating System : W11 Pro
Server Model: NodeJS

In the above SA, variable a has incorrect formatter, which throws an error. This is caught correctly in catch $_ERROR and returned.

{
    "hello": {
        "hello": "123"
    },
    "err": "Parser Error: Formatter \"spalit\" does not exist, expression {{hello.spalit(',')}}"
}

But if I disable this step and enable the API step, error is not captured in $_ERROR. The URL configured in api step returns 500 (response code does not affect the bug here).

{
    "hello": {
        "hello": "123"
    }
}

SA file: test-throw.zip (508 Bytes)

Identified this issue while debugging a user complaint. This is in production environment, so if it can be fixed urgently, it would be helpful.

Sounds like the same as API Action Throw error not populating $_ERROR

Or is it different?

1 Like

Its the same. Did not notice your post. It might have been suggested while I was creating this one.

@patrick Any chance you can share a fix for this?

I did some testing and the try/catch do work correctly. The problem is that the $_ERROR is not having the correct error, it seems to be undefined. The set value step didn't output because of this, using error: {{$_ERROR}} as expression will output the step but only with value error: since the $_ERROR is undefined.

Following should update should fill the $_ERROR with the correct error:

core.zip (2.2 KB) Unzip to lib/modules.

Yes, that was the problem.
I can see data in $_ERROR now, but its weirdly formatted.
image

There is status code here, followed by the error message. Can this be improved? Its very difficult to read in this state.

If you have a good suggestion on how to handle the response than let me know. It should be a generic solution not only for 500 errors but also for 404 Not found, authorization errors, gateway errors, rate limits etc.

I made a small update that you can test, it will first try to parse the body if it is content-type json and then use the message or error property for $_ERROR.

api.zip (1.6 KB) Unzip to lib/modules.

if (throwErrors && res.statusCode >= 400) {
    return reject({"status": res.statusCode, "response": (body.message || body.error || body)});
}

Would something like this make sense?
Since $_ERROR is expected to be an object (like other $_ items like $_POST, $_ENV), this makes sense to me.
The content of response you have already handled specifically for JSON type, and would remain as is for others.

Thx, the reject should probably indeed return an error like object or an actual Error object and not a string. The $_ERROR is filled with the message property from the Error object and not the object itself. I don't think we should change that current behavior of $_ERROR since users could already depend on it. Perhaps add an extra $_ERROR_OBJECT that contains the full error object.

Yes, you are right. I did not remember the $_ERROR object type correctly.
In that case, your last change is indeed correct.

Having another option for the complete object does sound very useful. Maybe $_EXCEPTION for the name?

@patrick The charCodeAt line was moved from top to bottom, which is causing the API to return an exception in case of OK response.
Weirdly it did not come up until I deployed this to production today. Systems we disrupted for quite a few minutes due to this.

What is the exception you are getting? It should only get to that code when it was a successful response with a body and it was always on that position.

charCodeAt function not found.

Here's the change:

It should be after line 96 on right.

Ah yes, it was an adjusted file that I send you. I hadn't committed that change in our version control and currently not on my work pc.

You are correct that the check and stripping of the BOM should happen before the JSON parse.

I've updated the code, also returning an error object now on reject instead of a string. Also added $_EXCEPTION to contain the error object.

Updated files:

api.zip (1.6 KB) unzip to lib/modules
app.zip (6.0 KB) unzip to lib/core

1 Like

I will do another update later, instead of the standard Error object it should be a custom Error which will contain the status code and body content.

1 Like

Updated api returning custom HttpError object: api.zip (1.6 KB)

1 Like

Thanks. Will be able to test these tomorrow.

Outputs seems to be misconfigured with the latest files.
I just see "HTTP Error 500" in $_ERROR. And null in $_EXCEPTION.
Earlier, I was at least getting the error message in ERROR being returned.
I did a console log, and I can see the complete response body containing error as returned from the API call.

Also there seems to be a duplicate condition for passErrors:

if (passErrors && res.statusCode >= 400) {
                        if (passErrors) {
...

The inner if statement is indeed not needed, will remove that.

The default message for Http Errors is indeed HTTP Error ${status}, the $_EXCEPTION should contain the error object with $_EXCEPTION.status having the status code and $_EXCEPTION.body holding the response body.