{"record":{"id":"6b5b9886e97fe7f3","repo":"microsoft/aspire","slug":"unsupported-mcp-approval-mode-global","errorCode":null,"errorMessage":"Unsupported MCP approval mode '{global}'.","messagePattern":"Unsupported MCP approval mode '(.+?)'\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxToolDefinition.cs","lineNumber":277,"sourceCode":"        if (always?.ReadOnly is { } alwaysReadOnly && never?.ReadOnly == alwaysReadOnly)\n        {\n            throw new ArgumentException(\n                $\"MCP tools with read_only set to '{alwaysReadOnly.ToString().ToLowerInvariant()}' cannot both always and never require approval.\",\n                nameof(policy));\n        }\n\n        return new(policy.Global, always, never);\n    }\n\n    public void WriteTo(Utf8JsonWriter writer)\n    {\n        if (Global is { } global)\n        {\n            writer.WriteStringValue(global switch\n            {\n                FoundryToolboxMcpGlobalApprovalMode.Never => \"never\",\n                FoundryToolboxMcpGlobalApprovalMode.Always => \"always\",\n                _ => throw new InvalidOperationException($\"Unsupported MCP approval mode '{global}'.\")\n            });\n            return;\n        }\n\n        writer.WriteStartObject();\n        Always?.WriteTo(writer, \"always\");\n        Never?.WriteTo(writer, \"never\");\n        writer.WriteEndObject();\n    }\n}\n\ninternal sealed record ResolvedFoundryToolboxMcpApprovalFilter(\n    IReadOnlyList<string> ToolNames,\n    bool? ReadOnly)\n{\n    public static ResolvedFoundryToolboxMcpApprovalFilter? Create(\n        FoundryToolboxMcpApprovalFilter? filter,\n        string parameterName)","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxToolDefinition.cs#L259-L295","documentation":"WriteTo serializes the global approval mode to its wire string via a switch over Never/Always. If Global holds an unsupported enum value at serialization time, the default arm throws this InvalidOperationException. This is a defensive guard — Create normally rejects such values first, so hitting it indicates the value bypassed validation.","triggerScenarios":"A ResolvedFoundryToolboxMcpApprovalPolicy constructed directly (record constructor) with an out-of-range Global, skipping Create's validation; a new enum member added to FoundryToolboxMcpGlobalApprovalMode without updating this switch.","commonSituations":"Unit tests or other integrations building the resolved record manually; SDK/enum evolution between package versions.","solutions":["Always construct policies through ResolvedFoundryToolboxMcpApprovalPolicy.Create rather than the record constructor.","Only use FoundryToolboxMcpGlobalApprovalMode.Never and .Always.","Update the switch in WriteTo if a new enum member is legitimately added.","Catch InvalidOperationException during serialization and inspect the Global value in the message."],"exampleFix":"// before\nvar resolved = new ResolvedFoundryToolboxMcpApprovalPolicy((FoundryToolboxMcpGlobalApprovalMode)7, null, null);\n// after\nvar resolved = ResolvedFoundryToolboxMcpApprovalPolicy.Create(new FoundryToolboxMcpApprovalPolicy { Global = FoundryToolboxMcpGlobalApprovalMode.Never });","handlingStrategy":"try-catch","validationCode":"if (policy.Global is { } g && g is not (FoundryToolboxMcpGlobalApprovalMode.Never or FoundryToolboxMcpGlobalApprovalMode.Always))\n    throw new InvalidOperationException($\"Unsupported MCP approval mode '{g}'.\");","typeGuard":"static bool Serializable(ResolvedFoundryToolboxMcpApprovalPolicy p) =>\n    p.Global is null || p.Global is FoundryToolboxMcpGlobalApprovalMode.Never or FoundryToolboxMcpGlobalApprovalMode.Always;","tryCatchPattern":"try { policy.WriteTo(writer); }\ncatch (InvalidOperationException ex) when (ex.Message.StartsWith(\"Unsupported MCP approval mode\"))\n{ logger.LogError(ex, \"Policy bypassed Create validation; rebuild via Create().\"); }","preventionTips":["Build resolved policies only via ResolvedFoundryToolboxMcpApprovalPolicy.Create","Update WriteTo's switch when the enum gains new members","Add a serialization round-trip test for every enum member"],"tags":["foundry","mcp","approval-policy","serialization","enum","aspire"],"backgroundTag":"unsupported-enum-value","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}