Getting Error Information without triggering an Error?

I got smacked with a bit of knowledge the other day about getting information on errors even when they are not thrown. Check out the video:

https://youtu.be/rCn6_E0cHFM

In this video, Erik shares a “knowledge bomb” he picked up during a conversation with a Microsoft engineer from the Business Central product team. The topic: how to retrieve error information using GetLastErrorText() even when no AL error has actually been raised in your code. This is particularly useful in scenarios where a function returns an optional boolean (suppressing the error) but you still want to know what went wrong behind the scenes.

The Problem: Silent Failures

In Business Central AL development, many functions have optional return values. A great example is HttpClient.Get(). If you consume the return value — for instance, by wrapping the call in an if statement — the runtime won’t throw an error when the call fails. Instead, it simply returns false.

This is by design. The documentation tells you that if the request fails and you try to access certain properties of the response (like HTTP content), you’ll get an error. But if you’re handling the return value properly, no error is raised. The downside? You traditionally had no easy way to find out what went wrong.

Or so Erik thought — until he learned otherwise.

The Knowledge Bomb: GetLastErrorText() Works Without an Error

The key insight is that GetLastErrorText() gets populated even when no AL error is thrown. In the case of HttpClient.Get(), if the call fails internally (for example, due to an invalid URI), the .NET runtime error information is still captured and made available through GetLastErrorText().

This means you can retrieve detailed error information — including the internal .NET stack trace — without your code execution being interrupted.

The Code

Here’s the complete example Erik walks through in the video. It’s a simple page extension on the Customer List that fires an HTTP GET request with a nonsensical URL on page open:

pageextension 50106 CustomerListExt extends "Customer List"
{
    trigger OnOpenPage()
    var
        Client: HttpClient;
        Response: HttpResponseMessage;
    begin
        if Client.Get('krjfvndkfjghszjfkgbdzkvjzsdfhbv', Response) then begin
            if Response.IsSuccessStatusCode() then
                message('All good! %1', Response.HttpStatusCode());
        end else
            message('%1', GetLastErrorText());
    end;
}

How It Works

  1. Client.Get() is called with a clearly invalid URL'krjfvndkfjghszjfkgbdzkvjzsdfhbv' is not a valid URI.
  2. Because the return value is consumed (the call is inside an if statement), no AL error is raised. The call simply returns false.
  3. In the else branch, GetLastErrorText() is called. Even though no AL error occurred, this function returns the underlying .NET error information.

Understanding HttpClient.Get() Return Values

It’s important to understand what Client.Get() returning true or false actually means:

  • true — The HTTP call was technically completed from a communication perspective. This does not mean the server returned a success status. You could still get a 404, 500, or 401. That’s why you check Response.IsSuccessStatusCode() or Response.HttpStatusCode() separately.
  • false — The call never completed. The request couldn’t even be sent — for example, because the URI was invalid, there was no network connectivity, or the base address wasn’t set.

What You Actually Get Back

When Erik runs this code, the GetLastErrorText() returns a detailed .NET error message, something like:

“An invalid request URI was provided. Either the request URI must be an absolute URI or BaseAddress must be set.”

Along with the message, you get the internal .NET stack trace showing the execution path through the Business Central service tier — including calls like HttpClient.SendWithTelemetry, RunExternalAction, CheckRequestBeforeSend, and PrepareRequest.

This is incredibly valuable for debugging. Instead of just knowing “the call failed,” you now know exactly why it failed.

Why This Matters

Erik notes that in his previous understanding, GetLastErrorText() was only populated when an actual AL error was raised — for instance, when calling a codeunit with Codeunit.Run() and catching the error. The fact that it’s also populated by internal .NET exceptions that are silently handled by the runtime is a significant and useful behavior.

This likely came about as part of Microsoft’s ongoing improvements to error handling in AL (the “error info updates”), but regardless of when it was introduced, it’s a powerful tool to have in your arsenal.

A Word of Caution

The error text you get from GetLastErrorText() in these scenarios is a raw .NET exception message with a stack trace. This is not something you’d want to display to an end user. It’s developer-level diagnostic information. Use it for logging, telemetry, or debugging — but present something more user-friendly to your end users.

Where Else Does This Apply?

While the video demonstrates this with HttpClient.Get(), the same pattern likely applies anywhere in AL where a function has an optional return value that suppresses errors when consumed. Any time the runtime catches an internal exception and converts it to a false return value, GetLastErrorText() may give you access to the underlying error details.

Summary

GetLastErrorText() is more powerful than many developers realize. It doesn’t just capture AL errors — it also captures internal .NET exceptions that occur behind the scenes, even when those exceptions are silently handled by the runtime. Next time you’re consuming a return value from a function like HttpClient.Get() and the call fails, don’t just settle for knowing it returned false. Call GetLastErrorText() and get the full picture of what went wrong.