{"record":{"id":"8268e01baecc5e1a","repo":"PrefectHQ/fastmcp","slug":"authorization-failed-for-resource-uri-missing","errorCode":null,"errorMessage":"Authorization failed for resource '{uri}': missing context","messagePattern":"Authorization failed for resource '(.+?)': missing context","errorType":"exception","errorClass":"AuthorizationError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/middleware/authorization.py","lineNumber":303,"sourceCode":"        context: MiddlewareContext[mt.ReadResourceRequestParams],\n        call_next: CallNext[mt.ReadResourceRequestParams, ResourceResult],\n    ) -> ResourceResult:\n        \"\"\"Check auth before resource read.\"\"\"\n        # STDIO has no auth concept, skip enforcement\n        from fastmcp.server.context import _current_transport\n\n        if _current_transport.get() == \"stdio\":\n            return await call_next(context)\n\n        # Get the resource being read\n        uri = context.message.uri\n        fastmcp = context.fastmcp_context\n        if fastmcp is None:\n            logger.warning(\n                f\"AuthMiddleware: fastmcp_context is None for resource '{uri}'. \"\n                \"Denying access for security.\"\n            )\n            raise AuthorizationError(\n                f\"Authorization failed for resource '{uri}': missing context\"\n            )\n\n        # get_resource/get_resource_template return None both when the resource\n        # does not exist and when component-level auth denied access, so the two\n        # cases are indistinguishable here. Keep the message ambiguous to avoid\n        # disclosing existence of resources the caller is not authorized to see.\n        version = _requested_version(context.message.meta)\n        component = await fastmcp.fastmcp.get_resource(str(uri), version=version)\n        if component is None:\n            component = await fastmcp.fastmcp.get_resource_template(\n                str(uri),\n                version=version,\n            )\n        if component is None:\n            raise AuthorizationError(\n                f\"Authorization failed for resource '{uri}': \"\n                \"not found or not authorized\"","sourceCodeStart":285,"sourceCodeEnd":321,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/middleware/authorization.py#L285-L321","documentation":"AuthMiddleware.on_read_resource fails closed when `context.fastmcp_context` is None for a resources/read request: without the request-scoped FastMCP Context it cannot perform authorization checks, so it denies access with an AuthorizationError. This guards against requests reaching auth middleware outside the normal context-establishing dispatch path.","triggerScenarios":"resources/read on a non-stdio transport where the MiddlewareContext was constructed without fastmcp_context — direct middleware invocation in tests, custom transports or ASGI glue that bypasses `Context` setup, or middleware wrapping that drops the request context.","commonSituations":"Hand-built MiddlewareContext in unit tests; embedding the low-level server in a custom HTTP handler that skips Context establishment; framework upgrades where custom transport code no longer matches FastMCP's context setup.","solutions":["Perform the read through the standard client -> server dispatch so FastMCP establishes the request Context.","In tests, wrap handler execution in `async with Context(fastmcp=mcp, session=...)` and pass it as fastmcp_context in MiddlewareContext.","Update custom transport/middleware glue to establish a FastMCP Context per request, mirroring the built-in transports.","Ensure the transport is registered so _current_transport is set correctly for the request."],"exampleFix":"# before (test)\nctx = MiddlewareContext(message=ReadResourceRequestParams(uri=uri), fastmcp_context=None)\nawait mw.on_read_resource(ctx, call_next)  # AuthorizationError: missing context\n# after\nasync with Context(fastmcp=mcp, session=session) as fctx:\n    ctx = MiddlewareContext(message=ReadResourceRequestParams(uri=uri), fastmcp_context=fctx)\n    await mw.on_read_resource(ctx, call_next)","handlingStrategy":"try-catch","validationCode":"async with Context(fastmcp=mcp, session=session) as fctx:\n    assert fctx is not None, 'resources/read middleware requires a FastMCP context'","typeGuard":null,"tryCatchPattern":"from fastmcp.exceptions import AuthorizationError\ntry:\n    res = await client.read_resource(uri)\nexcept AuthorizationError as e:\n    if 'missing context' in str(e):\n        logger.error('resources/read reached auth middleware without context; fix dispatch path')\n    else:\n        raise","preventionTips":["Never invoke middleware handlers directly outside the server dispatch pipeline.","Establish a FastMCP Context for every request in custom transports.","Update transport glue when upgrading FastMCP; context setup is an internal contract that evolves.","Watch for 'fastmcp_context is None' warnings — they indicate a harness/transport bug."],"tags":["auth","resources","middleware","fail-closed"],"backgroundTag":"authorization-failed","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}