From 68f66181885db87d0fc1f75e9c00934cf49ad2cd Mon Sep 17 00:00:00 2001 From: Shayne Boyer Date: Sun, 22 Mar 2026 11:31:23 -0400 Subject: [PATCH] Route error-producing spans through MapError for proper classification (#7239) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several high-volume code paths used EndWithStatus(err) which bypasses MapError() — the central error classification function. This caused errors to appear with raw Go type names or empty descriptions in telemetry, inflating the UnknownFailure bucket. Changes: - cmd/mcp.go: MCP tool handler now calls MapError(err, span) instead of EndWithStatus(err), giving MCP tool failures proper telemetry codes (e.g., service.arm.400 instead of azcore_ResponseError) - internal/agent/copilot_agent.go: Initialize() and ensureSession() now route errors through cmd.MapError for structured classification - internal/tracing/tracer.go: EndWithStatus() now prefixes error descriptions with 'internal.' to match MapError's catch-all convention, ensuring remaining callers in pkg/ (container_helper, extensions/manager) produce consistent internal.* codes Fixes #7239 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- cli/azd/.vscode/cspell.yaml | 3 +++ cli/azd/cmd/mcp.go | 6 +++++- cli/azd/internal/agent/copilot_agent.go | 11 +++++++++-- cli/azd/internal/tracing/tracer.go | 2 +- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/cli/azd/.vscode/cspell.yaml b/cli/azd/.vscode/cspell.yaml index 861728aec18..f4f38677b7c 100644 --- a/cli/azd/.vscode/cspell.yaml +++ b/cli/azd/.vscode/cspell.yaml @@ -92,6 +92,9 @@ dictionaryDefinitions: dictionaries: - azdProjectDictionary overrides: + - filename: cmd/mcp.go + words: + - internalcmd - filename: internal/tracing/fields/domains.go words: - azmk diff --git a/cli/azd/cmd/mcp.go b/cli/azd/cmd/mcp.go index 88a63d5e1f9..53e974fc878 100644 --- a/cli/azd/cmd/mcp.go +++ b/cli/azd/cmd/mcp.go @@ -14,6 +14,7 @@ import ( "github.com/azure/azure-dev/cli/azd/cmd/actions" "github.com/azure/azure-dev/cli/azd/internal" + internalcmd "github.com/azure/azure-dev/cli/azd/internal/cmd" "github.com/azure/azure-dev/cli/azd/internal/grpcserver" "github.com/azure/azure-dev/cli/azd/internal/mcp" "github.com/azure/azure-dev/cli/azd/internal/mcp/tools" @@ -152,7 +153,10 @@ func (a *mcpStartAction) Run(ctx context.Context) (*actions.ActionResult, error) } result, err = next(ctx, request) - span.EndWithStatus(err) + if err != nil { + internalcmd.MapError(err, span) + } + span.End() return result, err } diff --git a/cli/azd/internal/agent/copilot_agent.go b/cli/azd/internal/agent/copilot_agent.go index 33bf4825a52..0e185aa7eb3 100644 --- a/cli/azd/internal/agent/copilot_agent.go +++ b/cli/azd/internal/agent/copilot_agent.go @@ -21,6 +21,7 @@ import ( "github.com/azure/azure-dev/cli/azd/internal/agent/consent" agentcopilot "github.com/azure/azure-dev/cli/azd/internal/agent/copilot" + "github.com/azure/azure-dev/cli/azd/internal/cmd" "github.com/azure/azure-dev/cli/azd/internal/tracing" "github.com/azure/azure-dev/cli/azd/internal/tracing/events" "github.com/azure/azure-dev/cli/azd/internal/tracing/fields" @@ -86,7 +87,10 @@ func (a *CopilotAgent) Initialize(ctx context.Context, opts ...InitOption) (resu fields.CopilotInitReasoningEffort.String(result.ReasoningEffort), ) } - span.EndWithStatus(err) + if err != nil { + cmd.MapError(err, span) + } + span.End() }() options := &initOptions{} @@ -600,7 +604,10 @@ func (a *CopilotAgent) ensureSession(ctx context.Context, resumeSessionID string if sessionID != "" { span.SetAttributes(fields.StringHashed(fields.CopilotSessionId, sessionID)) } - span.EndWithStatus(err) + if err != nil { + cmd.MapError(err, span) + } + span.End() }() isResume := resumeSessionID != "" diff --git a/cli/azd/internal/tracing/tracer.go b/cli/azd/internal/tracing/tracer.go index f7c495b5872..af38e08d437 100644 --- a/cli/azd/internal/tracing/tracer.go +++ b/cli/azd/internal/tracing/tracer.go @@ -107,7 +107,7 @@ func (s *wrapperSpan) End(options ...trace.SpanEndOption) { func (s *wrapperSpan) EndWithStatus(err error, options ...trace.SpanEndOption) { if err != nil { - s.span.SetStatus(codes.Error, errorDescription(err)) + s.span.SetStatus(codes.Error, "internal."+errorDescription(err)) } else { s.span.SetStatus(codes.Ok, "") }