You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The host-side gRPC error path in cli/azd/internal/grpcserver/server.go relies on wrapErrorWithSuggestion() to append user guidance into the status message string. Recent work improved two adjacent areas:
The host gRPC error shaping path remains a separate, older mechanism that serializes actionable guidance primarily through message text.
Problem
wrapErrorWithSuggestion() mixes auth classification, gRPC status code selection, and "preserve actionable guidance" by concatenating suggestion text into status.Message(). That works but is brittle: it drops Links and any future guidance metadata from *internal.ErrorWithSuggestion, and it keeps auth semantics and actionable UX guidance too tightly coupled in one transport path.
Goal
Reshape host-side gRPC error handling into a single structured mapping path that:
preserves semantic classification, including auth subtype details
preserves actionable guidance (suggestion, links) as typed data, not message text
avoids relying on string concatenation as the transport contract
Proposed approach
Extract the current wrapErrorWithSuggestion() logic from server.go into a dedicated host gRPC error-mapping helper (internal/grpcserver/errors.go) and rename it to something descriptive (e.g. mapHostError).
auth subtype remains in structured ErrorInfo (azd.auth)
azd-local auth conditions use AUTH_*
Entra-originated failures preserve the raw AADSTS<code> reason
Introduce a structured gRPC detail (ActionableErrorDetail { suggestion, links }) so *internal.ErrorWithSuggestion can round-trip actionable guidance as typed data.
Teach pkg/azdext consumers (ErrorSuggestion, ErrorMessage, ErrorLinks) to read the new detail in addition to existing LocalError / ServiceError sources.
Stop appending suggestion text into status.Message. The user-facing message becomes ErrorWithSuggestion.Message (or err.Error()); guidance travels separately.
Collapse the duplicated grpcStatusFromError / wrapErrorLinks helpers that exist in both internal/grpcserver and pkg/azdext into single exported azdext versions consumed by both sides.
Scope
cli/azd/internal/grpcserver/server.go and a new internal/grpcserver/errors.go
new ActionableErrorDetail proto in cli/azd/grpc/proto/errors.proto
pkg/azdext consumer parsing and helper consolidation
Duplicated gRPC status / link helpers are consolidated.
Tests cover unary and streaming paths and assert that suggestion text no longer appears in status.Message.
Out of scope (explicitly excluded after discussion)
Preserving the Go error chain across the gRPC boundary. gRPC is a serialization boundary; only typed details (auth reason, actionable guidance) cross it. The wrapped chain on the host side is not reconstructible on the extension side and would not be useful if it were.
Adding message to ActionableErrorDetail. That would create a fourth message channel duplicating status.Message. The user-facing message belongs in status.Message; the detail carries only what status.Message cannot.
String-concatenation compatibility fallback. The previous shim protected no real out-of-tree consumer. Removing it lets the structured path be the single source of truth.
Context
Follow-up to the transport/auth work split across:
Summary
The host-side gRPC error path in
cli/azd/internal/grpcserver/server.gorelies onwrapErrorWithSuggestion()to append user guidance into the status message string. Recent work improved two adjacent areas:AADSTS530084and include auth error details when emitted asErrorWithSuggestionin telemetry #7797 adds structured auth classification for host → extension gRPC calls viacodes.Unauthenticated+google.rpc.ErrorInfoin theazd.authdomain. azd-local conditions useAUTH_*reasons; Entra-originated failures preserve the rawAADSTS<code>reason.ExtensionError.The host gRPC error shaping path remains a separate, older mechanism that serializes actionable guidance primarily through message text.
Problem
wrapErrorWithSuggestion()mixes auth classification, gRPC status code selection, and "preserve actionable guidance" by concatenating suggestion text intostatus.Message(). That works but is brittle: it dropsLinksand any future guidance metadata from*internal.ErrorWithSuggestion, and it keeps auth semantics and actionable UX guidance too tightly coupled in one transport path.Goal
Reshape host-side gRPC error handling into a single structured mapping path that:
Proposed approach
wrapErrorWithSuggestion()logic fromserver.gointo a dedicated host gRPC error-mapping helper (internal/grpcserver/errors.go) and rename it to something descriptive (e.g.mapHostError).AADSTS530084and include auth error details when emitted asErrorWithSuggestionin telemetry #7797 auth contract:codes.Unauthenticated)ErrorInfo(azd.auth)AUTH_*AADSTS<code>reasonActionableErrorDetail { suggestion, links }) so*internal.ErrorWithSuggestioncan round-trip actionable guidance as typed data.pkg/azdextconsumers (ErrorSuggestion,ErrorMessage,ErrorLinks) to read the new detail in addition to existingLocalError/ServiceErrorsources.status.Message. The user-facing message becomesErrorWithSuggestion.Message(orerr.Error()); guidance travels separately.grpcStatusFromError/wrapErrorLinkshelpers that exist in bothinternal/grpcserverandpkg/azdextinto single exportedazdextversions consumed by both sides.Scope
cli/azd/internal/grpcserver/server.goand a newinternal/grpcserver/errors.goActionableErrorDetailproto incli/azd/grpc/proto/errors.protopkg/azdextconsumer parsing and helper consolidationNon-goals
AADSTS530084and include auth error details when emitted asErrorWithSuggestionin telemetry #7797 beyond auth error classification.Acceptance criteria
azd.authErrorInfocontract from PR Provide error suggestions forAADSTS530084and include auth error details when emitted asErrorWithSuggestionin telemetry #7797 (AUTH_*for azd-local conditions;AADSTS<code>for Entra-originated failures).*internal.ErrorWithSuggestionround-trips suggestion and links as typedActionableErrorDetaildata, not via string parsing.pkg/azdextextractors (ErrorSuggestion,ErrorMessage,ErrorLinks) surface host-attached actionable detail.status.Message.Out of scope (explicitly excluded after discussion)
messagetoActionableErrorDetail. That would create a fourth message channel duplicatingstatus.Message. The user-facing message belongs instatus.Message; the detail carries only whatstatus.Messagecannot.Context
Follow-up to the transport/auth work split across:
AADSTS530084and include auth error details when emitted asErrorWithSuggestionin telemetry #7797