Skip to content

[AzureBackup] Surface RequestFailedException on dual-backend vault list failure; tolerate DPP policy FormatException#2805

Merged
shrja-ms merged 3 commits into
microsoft:mainfrom
shrja-ms:user/azurebackup-fix-vault-list-and-policy-format
Jun 9, 2026
Merged

[AzureBackup] Surface RequestFailedException on dual-backend vault list failure; tolerate DPP policy FormatException#2805
shrja-ms merged 3 commits into
microsoft:mainfrom
shrja-ms:user/azurebackup-fix-vault-list-and-policy-format

Conversation

@shrja-ms

@shrja-ms shrja-ms commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes Issue 5, Issue 6 from weekly telemetry, plus customer 4xx UX improvements and KQL classifier update.

Issue 5 — vault_get InvalidOperationException 422

When both RSV and DPP backends fail in ListVaultsAsync, the Task.WhenAll result was surfacing as a raw InvalidOperationException (classified as MCP bug). Now AzureBackupService.ListVaultsAsync unwraps the AggregateException and re-throws a RequestFailedException with the original HTTP status code, so the error is correctly classified as an Azure Service error.

Issue 6 — policy_get FormatException 500

Same Azure SDK XmlConvert.ToTimeSpan family bug as Issue 2 (azure-sdk-for-net#59306) but in policy retention deserializer (DataProtectionBackupAbsoluteDeleteSetting). Applied the same try/catch workaround:

  • DppBackupOperations.GetPolicyAsync: catch FormatException and fall back to listing all policies + matching by name
  • DppBackupOperations.ListPoliciesAsync: tolerate per-item FormatException during enumeration with a consecutive-failure cap (max 3)

Customer 4xx UX — actionable error messages

  • RecoveryPointGetCommand: added BMSUserErrorContainerNameIncorrectFormat error message with guidance to use fully qualified container name, plus 403 AuthorizationFailed message with RBAC role hint
  • ProtectedItemGetCommand: added BMSUserErrorContainerNameIncorrectFormat, BMSUserErrorProtectedItemNameIncorrectFormat, and 403 error messages

KQL telemetry classifier fix

Updated all 3 classification blocks in kql-queries.md and the decision tree in SKILL.md:

  • ValidationError → Customer (was Unknown — 19 hits/wk, user omitted required options)
  • System.UnauthorizedAccessException → Customer (was Unknown — 7 hits/wk, broken credentials)
  • Azure.Identity.CredentialUnavailableException → Customer (2 hits/wk, auth not configured)

This reclassifies all 26 "Unknown" hits from last week into the correct Customer bucket.

Changes

File Change
AzureBackupService.cs Unwrap AggregateException from dual-backend vault list; re-throw RequestFailedException with original status
DppBackupOperations.cs GetPolicyAsync FormatException fallback; ListPoliciesAsync per-item FormatException tolerance with cap
RecoveryPointGetCommand.cs Actionable error messages for container-name format + 403 RBAC
ProtectedItemGetCommand.cs Actionable error messages for container-name/item-name format + 403 RBAC
kql-queries.md Add ValidationError, UnauthorizedAccessException, CredentialUnavailableException → Customer
SKILL.md Update error classification decision tree
changelog-entries/*.yml Changelog entry
AzureBackupServiceTests.cs Tests for dual-backend failure scenarios

Invoking Livetests

Copilot submitted PRs are not trustworthy by default. Users with write access to the repo need to validate the contents of this PR before leaving a comment with the text /azp run mcp - pullrequest - live. This will trigger the necessary livetest workflows to complete required validation.

NEW-5: When azurebackup_vault_list and azurebackup_governance_find-unprotected

have both RSV and DPP backends fail with RequestFailedException, surface a single

RequestFailedException (preserving HTTP status and combining both messages) instead

of an InvalidOperationException so the failure is correctly classified as an Azure

service error rather than an MCP-side bug.

NEW-6: Fix azurebackup_policy_get and azurebackup_policy_list (DPP vaults) failing

with FormatException from XmlConvert.ToTimeSpan when policies contain ISO 8601

duration values the Azure SDK cannot parse. policy_list now skips unparseable

policies; policy_get falls back to listing the vault's policies and matching by name.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR delivers two AzureBackup toolset reliability fixes driven by production telemetry: (1) preserve Azure service error classification when both vault-list backends fail with RequestFailedException, and (2) tolerate Azure SDK FormatException during DPP policy materialization so callers can still retrieve usable policy data.

Changes:

  • Return a RequestFailedException (instead of InvalidOperationException) when both RSV and DPP vault listing operations fail with RequestFailedException, preserving an actionable HTTP status.
  • Add FormatException-tolerant logic for DPP policy_get/policy_list by falling back to listing + matching and by custom-enumerating results.
  • Update unit tests for the revised vault-list exception behavior and add a changelog entry documenting both fixes.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
tools/Azure.Mcp.Tools.AzureBackup/src/Services/AzureBackupService.cs Adjusts dual-backend vault-list failure wrapping to surface RequestFailedException and preserve status/error details.
tools/Azure.Mcp.Tools.AzureBackup/src/Services/DppBackupOperations.cs Adds FormatException tolerance for DPP policy get/list to avoid total failure on SDK duration parsing issues.
tools/Azure.Mcp.Tools.AzureBackup/tests/Azure.Mcp.Tools.AzureBackup.Tests/Services/AzureBackupServiceTests.cs Updates/adds tests validating the new RequestFailedException wrapping behavior and non-zero status preference.
servers/Azure.Mcp.Server/changelog-entries/azurebackup-fix-vault-list-and-policy-format-exception.yml Documents the two bug fixes in the server changelog entry format.

Comment thread tools/Azure.Mcp.Tools.AzureBackup/src/Services/AzureBackupService.cs Outdated
shrja-ms added 2 commits June 3, 2026 11:39
…ot-break on per-item FormatException

1. AzureBackupService.BuildBothVaultListingsFailedException now picks one source

   exception (preferring non-zero HTTP status) and takes both Status and ErrorCode

   from it, so callers never see a mismatched (Status, ErrorCode) pair.

2. DppBackupOperations.ListPoliciesAsync and ListJobsAsync now continue past a

   single-item FormatException instead of breaking out of the enumerator. A small

   consecutive-failure cap (3) prevents infinite loops when the SDK enumerator is

   left in a permanently-broken state by a page-level deserialization failure.

   This also makes GetPolicyAsync's list-and-match fallback resilient to bad

   policies positioned before the requested one.

Adds a NEW-5 test asserting the (Status, ErrorCode) pair is sourced consistently.
…rors; fix KQL classifier

- RecoveryPointGetCommand: add BMSUserErrorContainerNameIncorrectFormat and 403
  AuthorizationFailed error messages with guidance
- ProtectedItemGetCommand: add BMSUserErrorContainerNameIncorrectFormat,
  BMSUserErrorProtectedItemNameIncorrectFormat, and 403 error messages
- KQL classifier: add ValidationError, UnauthorizedAccessException, and
  CredentialUnavailableException to Customer bucket (reclassifies 26 Unknown hits)
- SKILL.md: update error classification decision tree to match
@shrja-ms shrja-ms enabled auto-merge (squash) June 9, 2026 15:03
@shrja-ms shrja-ms merged commit 1c5fd87 into microsoft:main Jun 9, 2026
15 checks passed
@github-project-automation github-project-automation Bot moved this from Untriaged to Done in Azure MCP Server Jun 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants