KQL · exceptions
Unhandled vs handled exceptions
Split exceptions by the handledAt value your SDK records and by whether their request failed, the practical test of whether an exception escaped.
exceptionsrequests exceptions
let lookback = 24h;
let failedOperations = requests
| where timestamp > ago(lookback)
| where tostring(success) =~ "false"
| distinct operation_Id;
exceptions
| where timestamp > ago(lookback)
| extend
handled_at = iff(isempty(handledAt), "(empty)", handledAt),
request_outcome = iff(operation_Id in (failedOperations), "request failed", "no failed request")
| summarize
exceptions = sum(itemCount),
types = dcount(type),
example_type = take_any(type)
by handled_at, request_outcome
| order by exceptions desc Returns: One row per handledAt value and request outcome, with the sampling-adjusted exception count, the number of distinct exception types and one example type.
Pitfalls
- Microsoft documents handledAt only as 'where the exception was seen'. Which values appear, and whether the column is filled at all, depends on the SDK, so read your own values before relying on them.
- An exception in an operation whose request failed didn't necessarily cause the failure, and one in a successful operation may still have been logged as an error. The split is a strong hint, not a proof.
- Exceptions from background work have no request, so they land in 'no failed request' whatever happened.
- The in operator reads up to 1,000,000 distinct values from the tabular expression. On a very busy resource with a long lookback, shorten the window.
How it works
The data model says an exception item represents “a handled or unhandled exception”, but the schema doesn’t give you a clean yes-or-no column for which. The classic handledAt column (HandledAt in the workspace) is described only as where the exception was seen, and SDKs differ in whether and how they fill it. So this query looks at the question from two sides: what the SDK recorded, and what happened to the request.
Line by line
let failedOperations = ...;lists theoperation_Idof every failed request in the window.distinctkeeps one row per ID.handled_atshows the recordedhandledAtvalue, with empty values labelled so they are visible as a row of their own.request_outcomeusesinwith the tabular expression to test whether the exception’s operation contains a failed request. An exception that escaped your handlers usually ends the request with a failure; one your code caught and tracked usually doesn’t.exceptions = sum(itemCount)counts exceptions the sampling-aware way;typesandexample_typeshow how varied each group is.
Reading the result
The “request failed” rows are the exceptions users felt. If the classic SDK’s exception tracking modules are on (the web module tracks unhandled exceptions in web apps; the Windows Server modules track unhandled and unobserved task exceptions in services and console apps), most escaped exceptions land there. A large “no failed request” group is the opposite: exceptions your code caught, tracked and survived. They are cheap to ignore and expensive to store; the pricing guide covers why volume matters.
Where handled_at has meaningful values for your SDK, compare them with the request outcome. The two should broadly agree; where they don’t, look at a few rows with exception details for a problem ID. The ASP.NET MVC and Web API guide explains which unhandled exceptions the classic SDK captures for you on .NET Framework.
Variations
- Which SDK fills the column: add
sdkVersionto thebyclause. - What else is recorded: run
exceptions | take 20 | project customDimensionsto see the properties your SDK attaches, and group by one that marks handled exceptions if it has one. - Workspace tables: use
AppExceptionsandAppRequests,TimeGenerated,HandledAt,OperationId,ExceptionType,SuccessandItemCount.
Sources, checked
- Azure Monitor Logs reference - AppExceptions (HandledAt)
- Application Insights telemetry data model (handled or unhandled exceptions)
- Application Insights Classic API 2.x (exception tracking modules)
- The case-sensitive in string operator (Kusto)
- Migrate an Application Insights classic resource to a workspace-based resource (table schemas)