Skip to content

Comments

Python: [BREAKING] Redesign Python exception hierarchy#4082

Merged
eavanvalkenburg merged 3 commits intomicrosoft:mainfrom
eavanvalkenburg:eavanvalkenburg/exception-hierarchy-redesign
Feb 19, 2026
Merged

Python: [BREAKING] Redesign Python exception hierarchy#4082
eavanvalkenburg merged 3 commits intomicrosoft:mainfrom
eavanvalkenburg:eavanvalkenburg/exception-hierarchy-redesign

Conversation

@eavanvalkenburg
Copy link
Member

Summary

Replaces the flat ServiceException family with domain-scoped exception branches, giving callers precise except targets and clear error semantics.

Fixes #3410

New Hierarchy

AgentFrameworkException
├── AgentException
│   ├── AgentInvalidAuthException
│   ├── AgentInvalidRequestException
│   ├── AgentInvalidResponseException
│   ├── AgentContentFilterException
│   └── DeclarativeLoaderError → ProviderLookupError
├── ChatClientException
│   ├── ChatClientInvalidAuthException
│   ├── ChatClientInvalidRequestException
│   ├── ChatClientInvalidResponseException
│   └── ChatClientContentFilterException
├── IntegrationException
│   ├── IntegrationInitializationError
│   ├── IntegrationInvalidAuthException
│   ├── IntegrationInvalidRequestException
│   ├── IntegrationInvalidResponseException
│   └── IntegrationContentFilterException
├── ContentError
│   └── AdditionItemMismatch
├── WorkflowException
│   ├── WorkflowRunnerException
│   │   ├── WorkflowConvergenceException
│   │   └── WorkflowCheckpointException
│   ├── WorkflowValidationError (+ Edge/Type/Graph suberrors)
│   ├── WorkflowActionError
│   └── DeclarativeWorkflowError
├── ToolException → ToolExecutionException
├── MiddlewareException → MiddlewareTermination
└── SettingNotFoundError

Breaking Changes

  • Removed: ServiceException, ServiceInitializationError, ServiceResponseException, ServiceContentFilterException, ServiceInvalidAuthError, ServiceInvalidExecutionSettingsError, ServiceInvalidRequestError, ServiceInvalidResponseError
  • Removed: AgentExecutionException (split → AgentInvalidRequestException / AgentInvalidResponseException)
  • Removed: AgentInvocationError (split → AgentInvalidRequestException / AgentInvalidResponseException)
  • Removed: AgentInitializationError, AgentSessionException, ChatClientInitializationError (0 callsites)
  • Removed: CheckpointDecodingError (merged → WorkflowCheckpointException)
  • Re-parented: Purview exceptions under IntegrationException hierarchy
  • Re-parented: Workflow exceptions under WorkflowException (moved from _workflows/_exceptions.py to exceptions.py)
  • Changed: Init validation errors now use built-in ValueError/TypeError instead of custom exceptions

Design Principles

  1. Domain-scoped branches: Agent, ChatClient, Integration, Content, Workflow, Tool, Middleware
  2. Consistent suberror pattern: InvalidAuth, InvalidRequest, InvalidResponse, ContentFilter across Agent/ChatClient/Integration
  3. Built-ins for validation: ValueError/TypeError for config checks; AF exceptions only for domain-level failures
  4. Catch-all still works: except AgentFrameworkException catches everything

Other Changes

  • _workflows/__init__.py emptied; main __init__.py imports directly from submodules
  • CODING_STANDARD.md updated with hierarchy design, rationale, and branch selection guide
  • 87 files changed across all packages (production + tests)
  • All 3729 tests pass, all 66 lint+pyright tasks pass

Copilot AI review requested due to automatic review settings February 19, 2026 12:38
@markwallace-microsoft markwallace-microsoft added documentation Improvements or additions to documentation python labels Feb 19, 2026
@github-actions github-actions bot changed the title [BREAKING] Redesign Python exception hierarchy Python: [BREAKING] Redesign Python exception hierarchy Feb 19, 2026
Copy link
Contributor

Copilot AI left a comment

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 implements a comprehensive redesign of the Python exception hierarchy to replace the flat ServiceException family with domain-scoped exception branches. This provides callers with precise exception targets and clear error semantics.

Changes:

  • Redesigned exception hierarchy with domain-specific branches (Agent, ChatClient, Integration, Workflow, Content, Tool, Middleware)
  • Removed old flat ServiceException family and replaced with semantically meaningful exceptions
  • Migrated initialization validation errors to use built-in Python exceptions (ValueError, TypeError, RuntimeError)
  • Consolidated workflow exceptions from _workflows/_exceptions.py into main exceptions.py
  • Updated comprehensive documentation in CODING_STANDARD.md with hierarchy diagrams, design principles, and usage guidance

Reviewed changes

Copilot reviewed 87 out of 87 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
python/packages/core/agent_framework/exceptions.py Complete redesign of exception hierarchy with 6 domain branches, each with consistent suberror patterns
python/CODING_STANDARD.md Comprehensive documentation of new hierarchy including design rationale, full tree diagram, and usage guide
python/packages/core/agent_framework/_workflows/_exceptions.py Deleted - workflow exceptions moved to main exceptions.py
python/packages/core/agent_framework/workflows/*.py Updated imports to use exceptions from main module instead of local _exceptions.py
python/packages/core/agent_framework/init.py Workflow imports changed from single _workflows import to individual submodule imports; workflow exceptions now exported from main exceptions module
python/packages/core/agent_framework/openai/* ServiceInitializationError → ValueError; ServiceInvalidRequestError → ChatClientInvalidRequestException; ServiceResponseException → ChatClientException
python/packages/core/agent_framework/azure/* Same pattern as OpenAI - init errors → ValueError, runtime errors → ChatClient* exceptions
python/packages/redis/agent_framework_redis/_context_provider.py ServiceInitializationError → ValueError; ServiceInvalidRequestError → IntegrationInvalidRequestException
python/packages/mem0/agent_framework_mem0/_context_provider.py ServiceInitializationError → ValueError for filter validation
python/packages/purview/agent_framework_purview/_exceptions.py PurviewServiceError now inherits from IntegrationException; PurviewAuthenticationError from IntegrationInvalidAuthException
python/packages/ollama/agent_framework_ollama/_chat_client.py ServiceInvalidRequestError → ChatClientInvalidRequestException; ServiceResponseException → ChatClientException
python/packages/foundry_local/agent_framework_foundry_local/_foundry_local_client.py ServiceInitializationError → ValueError for model validation
python/packages/declarative/agent_framework_declarative/_workflows/_executors_agents.py AgentInvocationError removed; replaced with AgentInvalidRequestException (not found) and AgentInvalidResponseException (invocation failure)
python/packages/declarative/agent_framework_declarative/_workflows/_factory.py DeclarativeWorkflowError now inherits from WorkflowException
python/packages/declarative/agent_framework_declarative/_workflows/_actions_error.py WorkflowActionError now inherits from WorkflowException
python/packages/declarative/agent_framework_declarative/_loader.py DeclarativeLoaderError now inherits from AgentException (was AgentFrameworkException)
python/packages/github_copilot/agent_framework_github_copilot/_agent.py ServiceException → AgentException; client not initialized → RuntimeError
python/packages/copilotstudio/agent_framework_copilotstudio/* ServiceException → AgentException; ServiceInitializationError → ValueError
python/packages/claude/agent_framework_claude/_agent.py ServiceException → AgentException; client not initialized → RuntimeError
python/packages/azure-ai/agent_framework_azure_ai/* ServiceInitializationError → ValueError; ServiceInvalidRequestError → IntegrationInvalidRequestException
python/packages/bedrock/agent_framework_bedrock/_chat_client.py ServiceInitializationError → ValueError; ServiceInvalidResponseError → ChatClientInvalidResponseException
python/packages/anthropic/agent_framework_anthropic/_chat_client.py ServiceInitializationError → ValueError for missing API key
All test files Updated to expect new exception types; ValueError for validation, domain-specific exceptions for runtime failures

@eavanvalkenburg eavanvalkenburg force-pushed the eavanvalkenburg/exception-hierarchy-redesign branch from f62042c to a66f2e3 Compare February 19, 2026 12:52
@eavanvalkenburg eavanvalkenburg requested a review from a team as a code owner February 19, 2026 13:01
@markwallace-microsoft
Copy link
Member

markwallace-microsoft commented Feb 19, 2026

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/ag-ui/agent_framework_ag_ui
   _run.py51012375%156–163, 209–210, 217, 340, 359–360, 375–376, 391, 419–421, 446, 449–452, 454–455, 458–464, 467–469, 472, 488–490, 497, 503–505, 509, 514–516, 518–519, 535–539, 550, 562, 566, 568–569, 585, 612–613, 668–670, 682–684, 887, 898–899, 906, 955–957, 974, 980, 988, 990, 998, 1028–1034, 1037–1040, 1042–1051, 1054, 1062–1065, 1072, 1075–1076, 1081, 1087–1089, 1093, 1098–1101, 1115–1117
packages/anthropic/agent_framework_anthropic
   _chat_client.py3863690%457, 544, 546, 689–690, 753, 774–775, 818–820, 822, 835–836, 843–845, 849–851, 855–858, 971, 981, 1015, 1037, 1158, 1185–1186, 1203, 1216, 1229, 1254–1255
packages/azure-ai-search/agent_framework_azure_ai_search
   _context_provider.py266398%103–104, 273
packages/azure-ai/agent_framework_azure_ai
   _agent_provider.py109199%249
   _chat_client.py4787584%391–392, 394, 578, 583–584, 586–587, 590, 593, 595, 600, 861–862, 864, 867, 870, 873–878, 881, 883, 891, 903–905, 909, 912–913, 921–924, 934, 942–945, 947–948, 950–951, 958, 966–967, 975–976, 981–982, 986–993, 998, 1001, 1009, 1015, 1023–1025, 1028, 1050–1051, 1184, 1212, 1227, 1343, 1465
   _client.py2743786%379, 381, 424, 432–444, 457, 517, 532–537, 580, 615, 617, 650, 858, 861, 864–865, 867–870, 913
   _project_provider.py116496%209, 303, 343, 376
   _shared.py2332190%109, 139, 187, 189–191, 223, 266, 278–280, 309, 311, 313, 317, 382, 413, 454, 461, 473, 492
packages/azurefunctions/agent_framework_azurefunctions
   _app.py50017265%261–262, 265, 267–269, 275, 277–280, 282–283, 285–287, 291, 294, 296, 298–299, 302–304, 306, 308, 316, 324–327, 330, 333, 338–339, 342–345, 348, 351–353, 364–367, 373, 375, 383–384, 387, 392–393, 395–396, 398, 401, 404, 406, 408, 410–412, 416–419, 421, 423–424, 426, 437–439, 443–444, 446–447, 449, 460–465, 473, 475, 481–483, 489–490, 492–493, 495–498, 502, 508, 527, 626–627, 735, 743–744, 764–766, 772–774, 780–782, 815–816, 876–877, 926–927, 932, 1014, 1017, 1026–1028, 1030–1032, 1034, 1036, 1047, 1049–1052, 1054, 1056–1057, 1059, 1066–1067, 1069–1070, 1072–1073, 1075, 1079, 1089–1091, 1093–1094, 1096–1098, 1105, 1107–1108, 1110, 1131, 1136, 1148, 1220, 1310, 1325–1328, 1353
   _context.py66690%98, 102, 153–154, 162, 169
   _serialization.py431174%40–46, 114–115, 129–130
packages/copilotstudio/agent_framework_copilotstudio
   _acquire_token.py420100% 
   _agent.py80396%170, 178, 295
packages/core/agent_framework
   _agents.py3314486%425, 429, 481, 846, 882, 898, 969, 974–977, 1038–1040, 1161, 1177, 1179, 1192, 1198, 1234, 1236, 1245–1250, 1255, 1257, 1263–1264, 1271, 1273–1274, 1282–1283, 1286–1288, 1296–1297, 1299, 1304, 1306
   _settings.py1161388%92, 99, 115, 126, 142–143, 145, 148, 251–252, 260–261, 266
   exceptions.py620100% 
packages/core/agent_framework/_workflows
   _agent.py3547080%66, 74–80, 116–117, 207, 253, 255, 313, 315, 361–362, 368–369, 375, 377, 382, 442–443, 452, 459, 485, 518–520, 522, 524, 526, 531, 536, 583, 613, 630, 669–672, 678, 684, 688–689, 692–698, 702–703, 711, 772, 779, 785–786, 797, 829, 836, 857, 866, 870, 872–874, 881
   _checkpoint.py157596%115–116, 274, 331–332
   _checkpoint_encoding.py50296%161–162
   _runner.py171298%276–277
   _validation.py152596%129, 150, 245, 326, 329
packages/core/agent_framework/azure
   _assistants_client.py370100% 
   _chat_client.py77494%298, 300, 313–314
   _entra_id_authentication.py220100% 
   _responses_client.py48687%184, 216, 276–279
   _shared.py71494%174, 177, 188, 198
packages/core/agent_framework/openai
   _assistant_provider.py106991%162, 288, 354, 469–474
   _assistants_client.py2753587%407, 409, 411, 414, 418–419, 422, 425, 430–431, 433, 436–438, 443, 454, 479, 481, 483, 485, 487, 492, 495, 498, 502, 513, 598, 684, 687, 716, 753–756, 826
   _chat_client.py2692291%201, 231–232, 236, 354, 361, 442–449, 451–454, 464, 549, 584, 600
   _exceptions.py330100% 
   _responses_client.py6247887%290–293, 297–298, 301–302, 308–309, 314, 327–333, 354, 362, 385, 548, 551, 606, 610, 612, 614, 616, 692, 702, 707, 750, 829, 846, 859, 1013, 1018, 1022–1024, 1028–1029, 1052, 1121, 1143–1144, 1159–1160, 1178–1179, 1317–1318, 1334, 1336, 1415–1423, 1542, 1597, 1612, 1651–1652, 1654–1656, 1670–1672, 1682–1683, 1689, 1704
   _shared.py1261687%65, 71–74, 148, 150, 152, 159, 161, 174, 249, 273, 332–333, 335
packages/declarative/agent_framework_declarative
   _loader.py24011552%311–317, 481–486, 517, 550–553, 556–558, 561–567, 594–600, 644–653, 655, 658, 660, 671, 675–681, 690, 692, 694, 700, 702, 704, 706, 708, 721–726, 733–738, 740, 744–754, 756–761, 769, 771, 776, 779–782, 785–786, 789–790, 804–805, 808–809, 827, 834–838
packages/declarative/agent_framework_declarative/_workflows
   _actions_error.py53786%100, 109–111, 116, 125, 133
   _declarative_base.py3784089%43, 46, 129–130, 133, 207, 221, 235, 246, 263, 398, 426, 509–511, 513–515, 517, 520, 527, 553, 577–581, 583–591, 612–613, 615–616
   _declarative_builder.py3422492%166, 223, 314, 336, 346, 397, 399, 407, 422, 458, 461, 487–488, 507–508, 584, 589, 633–635, 659–660, 882, 950
   _executors_agents.py4658681%95–96, 113–115, 156–157, 164, 192, 195–196, 204–205, 215, 226–231, 487, 525–527, 530, 546, 562–566, 590, 595, 685, 691–696, 703, 727–728, 737–739, 788–789, 797, 816, 923–926, 933–934, 943–944, 956–961, 965–966, 968, 973, 975, 979–982, 985, 987–988, 991, 999–1001, 1003, 1006–1007, 1009, 1036–1037
   _executors_basic.py2813786%32, 307, 382, 384, 389–391, 404–410, 433, 438–441, 508, 513, 520–522, 526, 529, 533, 535, 540–542, 546, 548, 553–555, 558
   _executors_control_flow.py169696%81, 89, 152, 342–343, 347
   _executors_external_input.py1082675%131, 133–134, 136–137, 139, 192, 194, 197–198, 201–202, 204–205, 207, 259, 261, 263–264, 266, 326, 328, 331–333, 335
   _factory.py1386056%181, 258–259, 323–325, 333, 335, 338–344, 373, 384–385, 394, 429, 442, 467–470, 489–493, 496–497, 500, 503, 508, 617–618, 620–621, 623–625, 628, 642, 645–650, 653–654, 656, 659, 669–670, 672, 676–677, 679
packages/mem0/agent_framework_mem0
   _context_provider.py77198%128
packages/purview/agent_framework_purview
   _exceptions.py70100% 
packages/redis/agent_framework_redis
   _context_provider.py1795668%220, 238, 241, 247–248, 250–251, 253–255, 257–259, 261–263, 265–276, 278–279, 281–287, 315, 317, 321–326, 347, 358, 368–369, 382–383, 405, 407–408, 412–413
TOTAL21230330484% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
4183 239 💤 0 ❌ 0 🔥 1m 14s ⏱️

@eavanvalkenburg eavanvalkenburg added this pull request to the merge queue Feb 19, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to a conflict with the base branch Feb 19, 2026
eavanvalkenburg and others added 3 commits February 19, 2026 18:31
Replace the flat ServiceException family with domain-scoped branches:
- AgentException (with InvalidAuth, InvalidRequest, InvalidResponse, ContentFilter)
- ChatClientException (same consistent suberrors)
- IntegrationException (same + InitializationError)
- WorkflowException (Runner, Convergence, Checkpoint, Validation, Action, Declarative)
- ContentError (AdditionItemMismatch)
- ToolException / ToolExecutionException (unchanged)
- MiddlewareException / MiddlewareTermination (unchanged)

Key changes:
- All Service* exceptions removed (ServiceException, ServiceInitializationError, etc.)
- AgentExecutionException split into AgentInvalidRequest/ResponseException
- AgentInvocationError removed, split into AgentInvalidRequest/ResponseException
- Workflow exceptions moved from _workflows/_exceptions.py into main exceptions.py
- _workflows/__init__.py emptied; main __init__.py imports directly from submodules
- Purview exceptions re-parented under IntegrationException hierarchy
- Init validation errors use built-in ValueError/TypeError instead of custom exceptions
- CODING_STANDARD.md updated with hierarchy design and rationale

Fixes microsoft#3410

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ToolException: base class for all tool-related exceptions (preconditions,
connection/init failures).
ToolExecutionException: runtime call failures (tool call failed, reconnect
failed, MCP errors).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- azurefunctions: _context.py, _app.py, _serialization.py, test_func_utils.py
  used 'from agent_framework._workflows import X' which broke after
  emptying _workflows/__init__.py; changed to direct submodule imports
- azure-ai-search: test still referenced ServiceInitializationError;
  updated to ValueError to match production code

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@eavanvalkenburg eavanvalkenburg force-pushed the eavanvalkenburg/exception-hierarchy-redesign branch from 0baee84 to bc3d923 Compare February 19, 2026 17:31
@eavanvalkenburg eavanvalkenburg added this pull request to the merge queue Feb 19, 2026
Merged via the queue into microsoft:main with commit 5ee0685 Feb 19, 2026
26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: all: Review and standardize exception documentation

4 participants