{"record":{"id":"38a00bfd1a164601","repo":"PrefectHQ/fastmcp","slug":"authorization-failed-for-resource-uri-not-fou","errorCode":null,"errorMessage":"Authorization failed for resource '{uri}': not found or not authorized","messagePattern":"Authorization failed for resource '(.+?)': not found or not authorized","errorType":"exception","errorClass":"AuthorizationError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/middleware/authorization.py","lineNumber":319,"sourceCode":"                \"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\"\n            )\n\n        # Global auth check\n        token = get_access_token()\n        ctx = AuthContext(token=token, component=component)\n        authorized, missing = await run_auth_checks_with_shortfall(self.auth, ctx)\n        if not authorized:\n            if missing:\n                missing = self._chain_shortfall(missing, ctx, fastmcp.fastmcp)\n                raise InsufficientScopeError(\n                    missing,\n                    message=(\n                        f\"Authorization failed for resource '{uri}': \"\n                        f\"insufficient scope (required: {', '.join(missing)})\"\n                    ),\n                )","sourceCodeStart":301,"sourceCodeEnd":337,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/middleware/authorization.py#L301-L337","documentation":"For resources/read, AuthMiddleware resolves the component via `get_resource(uri, version)` and, failing that, `get_resource_template(uri, version)`; when both return None it raises this AuthorizationError. Both 'does not exist' and 'exists but component-level auth hid it' map to the same deliberately ambiguous message so resource existence is not disclosed to unauthorized callers.","triggerScenarios":"Client requests a URI that matches no registered resource or resource template, a URI that doesn't match the template pattern (e.g. wrong parameter format for 'data://{id}'), a version requested via _meta with no matching variant, or component-level auth denying this caller so lookup returns None.","commonSituations":"URI escaping/format mismatches against a resource template (missing scheme, query instead of path parameter); client caching a URI from a renamed resource; versioned component variants removed; resource hidden by auth policy for this token.","solutions":["List resources/templates as the authorized client (`session.list_resources()` / `list_resource_templates()`) and use an exact returned URI.","Check the URI against the template pattern; supply parameters in the expected format (e.g. 'data://42' not 'data?id=42').","If the component requires auth, grant the caller's token the configured scopes/roles so the lookup stops being filtered.","Verify the requested version in _meta exists, or omit it to get the default variant."],"exampleFix":"# before\nawait client.read_resource('config://app')  # server only has 'config://{env}'\n# after\ntemplates = await client.list_resource_templates()\nuri = templates[0].uri_template.replace('{env}', 'prod')\nawait client.read_resource(uri)","handlingStrategy":"validation","validationCode":"uris = {str(r.uri) for r in await client.list_resources()}\nuris |= {t.uri_template for t in await client.list_resource_templates()}\nassert uri in uris, 'URI not visible to this caller; check format and auth'","typeGuard":null,"tryCatchPattern":"from fastmcp.exceptions import AuthorizationError\ntry:\n    res = await client.read_resource(uri)\nexcept AuthorizationError as e:\n    if 'not found or not authorized' in str(e):\n        known = await client.list_resources()\n        logger.warning('URI %s unavailable; known: %s', uri, [str(r.uri) for r in known])\n    else:\n        raise","preventionTips":["Copy URIs from list_resources/list_resource_templates responses instead of hand-writing them.","Match resource template URI format exactly (path parameters, scheme).","Check component-level auth config when a resource exists but is denied.","Avoid requesting _meta versions that may not exist; prefer defaults."],"tags":["auth","resources","middleware","access-control"],"backgroundTag":"authorization-failed","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}