Azure / Azure/azure-dev

Extension cancellations are classified as ext.run.failed instead of user.canceled

Open
#9,166 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
569
Forks
364
Avg merge
2d 19h
Merged PRs (30d)
136

Description

### Summary

When an interactive azd **extension** command is cancelled by the user, the cancellation is recorded in telemetry as `ext.run.failed` instead of a `user.canceled*` result code. This means extension cancellations are indistinguishable from real failures in telemetry, and any downstream metric that counts cancellations separately for extensions will always read 0.

### Root cause

In `cli/azd/internal/cmd/errors.go`, `classify()` checks error types in order. The `*extensions.ExtensionRunError` case returns early:

```go
// cli/azd/internal/cmd/errors.go
if _, ok := errors.AsType[*extensions.ExtensionRunError](err); ok {
return "ext.run.failed", nil
}
...
if code := classifySentinel(err); code != "" { // user.canceled* is classified here
return code, nil
}
```

The extension runner (`cli/azd/pkg/extensions/runner.go`) wraps **any** error from the extension process in `ExtensionRunError`:

```go
return &runResult, &ExtensionRunError{Err: err, ExtensionId: extension.Id}
```

Because the `ExtensionRunError` check (errors.go:108) runs **before** the cancellation classification (`classifySentinel`, errors.go:140), a cancelled extension run is classified as `ext.run.failed` and the underlying `user.canceled*` sentinel is never reached.

### Impact

- Extension cancellations are counted as failures (`ext.run.failed`) in `RawEventsAppRequests`.
- Success/failure rates for extension commands (`ext.run`) are understated for reliability because user cancellations are lumped in with genuine failures.
- Downstream cooked tables (e.g. an `AzdExtensionCommands` table in `azure-dev-tools`) cannot populate a `CanceledInv`/cancellation metric for extensions.

### Proposed fix

Make cancellation classification take precedence over `ExtensionRunError` so a cancelled extension run emits a distinct `user.canceled*` (or a dedicated `ext.run.canceled`) result code. Options:

1. In `classify()`, unwrap `ExtensionRunError` and check for cancellation sentinels **before** returning `ext.run.failed`, or
2. In the extension runner, detect cancellation and return the cancellation error directly rather than wrapping it in `ExtensionRunError`.

### Notes

- Historical `ext.run.failed` rows cannot be reclassified retroactively; the fix only affects data emitted after it ships.
- Discovered while adding an `AzdExtensionCommands` telemetry table in the internal `azure-dev-tools` repo (coreai-microsoft/azure-dev-tools#96).

Contributor guide

Open the contributing guide

Research direction

Start in cli/azd/internal/cmd/errors.go at classify(), then inspect cli/azd/pkg/extensions/runner.go and the ExtensionRunError wrapper. Verify how cancellation sentinels are propagated and choose a classification path that preserves user.canceled* for canceled extension runs while retaining ext.run.failed for real failures.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
cli, observability
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.