Skip to content

Let FastMCPError propagate unchanged from managers#2697

Merged
jlowin merged 1 commit intorelease/2.xfrom
fix/propagate-fastmcp-errors
Dec 23, 2025
Merged

Let FastMCPError propagate unchanged from managers#2697
jlowin merged 1 commit intorelease/2.xfrom
fix/propagate-fastmcp-errors

Conversation

@jlowin
Copy link
Copy Markdown
Member

@jlowin jlowin commented Dec 23, 2025

Previously, managers only re-raised their specific error types (e.g., ToolError in ToolManager, ResourceError in ResourceManager). This meant that other FastMCPError subclasses like fastmcp.exceptions.ValidationError would get wrapped, losing their original message.

Now all managers catch FastMCPError (the base class) and re-raise it unchanged, allowing any FastMCP error type to propagate with its original message intact.

from fastmcp import FastMCP
from fastmcp.server import Context
from fastmcp.exceptions import ValidationError

mcp = FastMCP()

@mcp.tool
def validate(ctx: Context) -> str:
    raise ValidationError("Invalid input format")
    
# Error message is now "Invalid input format", not wrapped in "Error calling tool..."

@marvin-context-protocol marvin-context-protocol Bot added bug Something isn't working. Reports of errors, unexpected behavior, or broken functionality. server Related to FastMCP server implementation or server-side functionality. labels Dec 23, 2025
@jlowin
Copy link
Copy Markdown
Member Author

jlowin commented Dec 23, 2025

Merging, this needs the uvicorn 0.39 fixes in #2696

@jlowin jlowin merged commit 7a46e21 into release/2.x Dec 23, 2025
6 of 10 checks passed
@jlowin jlowin deleted the fix/propagate-fastmcp-errors branch December 23, 2025 23:29
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 23, 2025

Walkthrough

FastMCPError is added to the public exception imports across three manager modules: prompt_manager, resource_manager, and tool_manager. Exception handling logic in each module is updated to specifically re-raise FastMCPError without custom processing, while general exception handling paths remain intact with existing error masking behavior preserved. This change unifies exception propagation behavior across the managers.

Possibly related PRs

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the primary change: allowing FastMCPError to propagate unchanged from manager components rather than being caught and wrapped.
Description check ✅ Passed The description clearly explains the problem, solution, and includes a practical code example, but the contributors checklist items are not checked off.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/propagate-fastmcp-errors

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/fastmcp/tools/tool_manager.py (1)

161-164: LGTM: Exception handling correctly preserves FastMCPError and pydantic validation errors.

The exception handling logic correctly:

  • Re-raises all FastMCPError subclasses (including fastmcp.exceptions.ValidationError) unchanged
  • Re-raises pydantic.ValidationError (imported at line 8) unchanged
  • Preserves existing error masking behavior for all other exceptions

The dual handling ensures both FastMCP-specific errors and pydantic validation errors propagate with their original messages intact, which aligns with the PR objectives.

Optional: Add clarifying comment

To make the intent more explicit, consider adding a brief comment distinguishing the pydantic ValidationError:

         except FastMCPError:
             raise
+        # pydantic ValidationError (distinct from fastmcp.exceptions.ValidationError)
         except ValidationError:
             raise
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf60ac4 and a46a476.

📒 Files selected for processing (3)
  • src/fastmcp/prompts/prompt_manager.py
  • src/fastmcp/resources/resource_manager.py
  • src/fastmcp/tools/tool_manager.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Use Python ≥ 3.10 with full type annotations
Never use bare except - be specific with exception types

Files:

  • src/fastmcp/resources/resource_manager.py
  • src/fastmcp/prompts/prompt_manager.py
  • src/fastmcp/tools/tool_manager.py
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T21:37:55.031Z
Learning: Applies to src/fastmcp/__init__.py : All module exports should be intentional - only re-export to `fastmcp.*` for fundamental types like `FastMCP` and `Client`, prefer users importing from specific submodules for specialized features
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: .cursor/rules/core-mcp-objects.mdc:0-0
Timestamp: 2025-11-26T21:51:44.174Z
Learning: Review and update related Manager classes (ToolManager, ResourceManager, PromptManager) when modifying MCP object definitions
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T21:37:55.031Z
Learning: Applies to src/fastmcp/**/__init__.py : Core types that define a module's purpose should be exported (e.g., `Middleware` from `fastmcp.server.middleware`), while specialized features can live in submodules
📚 Learning: 2025-12-21T21:37:55.031Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T21:37:55.031Z
Learning: Applies to src/fastmcp/__init__.py : All module exports should be intentional - only re-export to `fastmcp.*` for fundamental types like `FastMCP` and `Client`, prefer users importing from specific submodules for specialized features

Applied to files:

  • src/fastmcp/resources/resource_manager.py
  • src/fastmcp/prompts/prompt_manager.py
  • src/fastmcp/tools/tool_manager.py
📚 Learning: 2025-11-26T21:51:44.174Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: .cursor/rules/core-mcp-objects.mdc:0-0
Timestamp: 2025-11-26T21:51:44.174Z
Learning: Review and update related Manager classes (ToolManager, ResourceManager, PromptManager) when modifying MCP object definitions

Applied to files:

  • src/fastmcp/resources/resource_manager.py
  • src/fastmcp/prompts/prompt_manager.py
  • src/fastmcp/tools/tool_manager.py
📚 Learning: 2025-12-21T21:37:55.031Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T21:37:55.031Z
Learning: Applies to src/fastmcp/**/__init__.py : Core types that define a module's purpose should be exported (e.g., `Middleware` from `fastmcp.server.middleware`), while specialized features can live in submodules

Applied to files:

  • src/fastmcp/prompts/prompt_manager.py
🧬 Code graph analysis (3)
src/fastmcp/resources/resource_manager.py (1)
src/fastmcp/exceptions.py (3)
  • FastMCPError (6-7)
  • NotFoundError (34-35)
  • ResourceError (14-15)
src/fastmcp/prompts/prompt_manager.py (1)
src/fastmcp/exceptions.py (3)
  • FastMCPError (6-7)
  • NotFoundError (34-35)
  • PromptError (22-23)
src/fastmcp/tools/tool_manager.py (2)
src/fastmcp/server/context.py (1)
  • fastmcp (169-174)
src/fastmcp/exceptions.py (3)
  • FastMCPError (6-7)
  • ToolError (18-19)
  • ValidationError (10-11)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Run tests: Python 3.13 on ubuntu-latest
  • GitHub Check: Run tests: Python 3.10 on windows-latest
  • GitHub Check: Run tests: Python 3.10 on ubuntu-latest
  • GitHub Check: Run tests with lowest-direct dependencies
🔇 Additional comments (7)
src/fastmcp/tools/tool_manager.py (1)

11-11: LGTM: FastMCPError import added.

The addition of FastMCPError to the imports enables the enhanced exception propagation behavior described in the PR objectives.

src/fastmcp/prompts/prompt_manager.py (2)

10-10: LGTM: FastMCPError import added.

The addition of FastMCPError to the imports is consistent with the pattern applied across all manager classes in this PR.


110-111: LGTM: Exception handling correctly preserves FastMCPError.

The exception handling logic correctly re-raises all FastMCPError subclasses (including PromptError) unchanged, while preserving the existing error masking behavior for other exceptions. This ensures that FastMCP-specific errors propagate with their original messages intact.

src/fastmcp/resources/resource_manager.py (4)

13-13: LGTM: FastMCPError import added.

The addition of FastMCPError to the imports enables consistent exception propagation behavior across the resource manager.


271-273: LGTM: Exception handling correctly preserves FastMCPError in template creation.

The exception handling logic correctly re-raises all FastMCPError subclasses unchanged when creating resources from templates, while preserving the existing error masking behavior for other exceptions.


301-303: LGTM: Exception handling correctly preserves FastMCPError in resource reads.

The exception handling logic correctly re-raises all FastMCPError subclasses unchanged when reading resources directly, while preserving the existing error masking behavior for other exceptions.


323-324: LGTM: Exception handling correctly preserves FastMCPError in template reads.

The exception handling logic correctly re-raises all FastMCPError subclasses unchanged when reading resources from templates, while preserving the existing error masking behavior for other exceptions. This completes the consistent exception propagation pattern across all resource manager code paths.

@marvin-context-protocol
Copy link
Copy Markdown
Contributor

Test Failure Analysis

Summary: The test failure in workflow run 20473894870 is unrelated to the changes in this PR.

Root Cause: The test test_nested_streamable_http_server_resolves_correctly is timing out during teardown due to a uvicorn cleanup issue. This is a pre-existing problem, not introduced by this PR's exception handling changes.

Evidence:

  • ✅ The test passes successfully, but hangs during asyncio event loop cleanup
  • ✅ The same test fails identically on the parent commit (bf60ac4), confirming this is not a regression from this PR
  • ✅ All manager-related tests pass (the actual code changed by this PR)
  • ✅ The failure occurs in pytest-asyncio fixture teardown trying to cancel pending tasks

This aligns with @jlowin's comment mentioning "uvicorn 0.39 fixes in #2696" - the test failure is related to that dependency issue, not the FastMCPError propagation changes in this PR.

Suggested Solution: Merge #2696 first (uvicorn 0.39 fixes), then this PR should pass CI cleanly.

Detailed Analysis

Test Failure Details

The failing test: tests/client/test_streamable_http.py::test_nested_streamable_http_server_resolves_correctly

Error:

ERROR at teardown of test_nested_streamable_http_server_resolves_correctly
Failed: Timeout (>5.0s) from pytest-timeout

The test itself passes, but uvicorn's lifespan manager has a pending task that prevents clean shutdown:

Task was destroyed but it is pending!
task: <Task cancelling name='Task-13173' coro=<LifespanOn.main()>>

Verification

I tested both the PR branch and the parent commit:

  • PR branch (a46a476): Test times out during teardown ❌
  • Parent commit (bf60ac4): Test times out during teardown ❌

This confirms the issue existed before this PR.

Files Changed by This PR

The PR only modified exception handling in three manager files:

  • src/fastmcp/tools/tool_manager.py
  • src/fastmcp/resources/resource_manager.py
  • src/fastmcp/prompts/prompt_manager.py

None of these changes affect HTTP server teardown or uvicorn lifecycle management.

Related Files

Failing test: tests/client/test_streamable_http.py (lines 240-280)
Relevance: Contains the timing out test, but unrelated to manager exception handling

Manager files (modified by this PR):

  • src/fastmcp/tools/tool_manager.py:155-170
  • src/fastmcp/resources/resource_manager.py:305-335
  • src/fastmcp/prompts/prompt_manager.py:115-130

Relevance: All manager tests pass; changes are working as intended

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working. Reports of errors, unexpected behavior, or broken functionality. server Related to FastMCP server implementation or server-side functionality.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant