@@ -169,6 +169,29 @@ def __init__(self, payload: dict[str, object] | None = None) -> None:
169169 self .payload = payload
170170
171171
172+ class PermissionReturnedAwaitableInSyncContextError (Exception ):
173+ """A permission returned an awaitable while being resolved synchronously.
174+
175+ Raised when a permission's ``has_permission`` returns an awaitable (for
176+ example a plain ``def`` that returns a coroutine) but the field is being
177+ resolved on the synchronous path, where the awaitable cannot be awaited.
178+ Returning it as-is would be truthy and silently grant access, so we fail
179+ closed instead.
180+ """
181+
182+ def __init__ (self , permission : object ) -> None :
183+ self .permission = permission
184+ permission_name = type (permission ).__name__
185+ message = (
186+ f"Permission { permission_name !r} returned an awaitable from "
187+ "`has_permission` but is being resolved synchronously, so the "
188+ "result cannot be awaited. Declare `has_permission` as "
189+ "`async def` so Strawberry runs it on the asynchronous path, or "
190+ "return a plain boolean."
191+ )
192+ super ().__init__ (message )
193+
194+
172195__all__ = [
173196 "ConflictingArgumentsError" ,
174197 "DuplicatedTypeName" ,
@@ -191,6 +214,7 @@ def __init__(self, payload: dict[str, object] | None = None) -> None:
191214 "MultipleStrawberryFieldsError" ,
192215 "ObjectIsNotAnEnumError" ,
193216 "ObjectIsNotClassError" ,
217+ "PermissionReturnedAwaitableInSyncContextError" ,
194218 "PrivateStrawberryFieldError" ,
195219 "ScalarAlreadyRegisteredError" ,
196220 "StrawberryException" ,
0 commit comments