Skip to content

is_docket_available() lacks version check, crashes when old pydocket is installed by another package #3803

@dsfaccini

Description

@dsfaccini

Claude here: opened on behalf of @dsfaccini, verified the MRE locally.

Summary

is_docket_available() only checks import docket — it doesn't verify the version. When another package (e.g. prefect) brings in pydocket<0.18.0, the check passes but subsequent imports of current_execution from docket.dependencies fail at runtime:

ImportError: cannot import name 'current_execution' from 'docket.dependencies'

This happens even though fastmcp[tasks] is not installed — the mere presence of an old pydocket in the environment is enough to trigger it.

Location

fastmcp/server/dependencies.pyget_task_context() (around line 117):

if is_docket_available():
    from docket.dependencies import current_execution  # crashes if pydocket < 0.18.0

Reproduction

# /// script
# requires-python = ">=3.10"
# dependencies = ["fastmcp==3.2.2", "pydocket==0.16.6"]
# ///
from fastmcp import FastMCP

server = FastMCP('test')

@server.tool()
def hello() -> str:
    return 'hello'

if __name__ == '__main__':
    import asyncio
    from fastmcp.client import Client
    from fastmcp.client.transports import FastMCPTransport

    async def main():
        async with Client(transport=FastMCPTransport(server)) as client:
            tools = await client.list_tools()
            print(tools)

    asyncio.run(main())

Context

This is a practical issue for projects with large dependency trees. For example, pydantic-ai depends on both fastmcp>=3.2.1 and prefect, and prefect declares pydocket>=0.16.2 (no upper bound). The lockfile resolver picks 0.16.6, which is valid for prefect but breaks fastmcp.

Previously reported in #3447 and closed, but the fix described there (using fastmcp[tasks]) doesn't apply here — we don't want or use docket/tasks, we just happen to have an old pydocket installed transitively.

Suggested fix

Make is_docket_available() version-aware, e.g.:

def is_docket_available() -> bool:
    try:
        import docket.dependencies
        return hasattr(docket.dependencies, 'current_execution')
    except ImportError:
        return False

Or guard the import with a try/except at the call site.

Metadata

Metadata

Assignees

No one assigned

    Labels

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

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions