{"record":{"id":"c344b0fdcd683b51","repo":"django/django","slug":"you-cannot-use-atomic-requests-with-async-views","errorCode":null,"errorMessage":"You cannot use ATOMIC_REQUESTS with async views.","messagePattern":"You cannot use ATOMIC_REQUESTS with async views\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"django/core/handlers/base.py","lineNumber":352,"sourceCode":"            raise ValueError(\n                \"%s didn't return an HttpResponse object. It returned None \"\n                \"instead.\" % name\n            )\n        elif asyncio.iscoroutine(response):\n            raise ValueError(\n                \"%s didn't return an HttpResponse object. It returned an \"\n                \"unawaited coroutine instead. You may need to add an 'await' \"\n                \"into your view.\" % name\n            )\n\n    # Other utility methods.\n\n    def make_view_atomic(self, view):\n        non_atomic_requests = getattr(view, \"_non_atomic_requests\", set())\n        for alias, settings_dict in connections.settings.items():\n            if settings_dict[\"ATOMIC_REQUESTS\"] and alias not in non_atomic_requests:\n                if iscoroutinefunction(view):\n                    raise RuntimeError(\n                        \"You cannot use ATOMIC_REQUESTS with async views.\"\n                    )\n                view = transaction.atomic(using=alias)(view)\n        return view\n\n    def process_exception_by_middleware(self, exception, request):\n        \"\"\"\n        Pass the exception to the exception middleware. If no middleware\n        return a response for this exception, return None.\n        \"\"\"\n        for middleware_method in self._exception_middleware:\n            response = middleware_method(request, exception)\n            if response:\n                return response\n        return None\n\n\ndef reset_urlconf(sender, **kwargs):","sourceCodeStart":334,"sourceCodeEnd":370,"githubUrl":"https://github.com/django/django/blob/ae25a40be07e8a749edf526df37c93e59d4a22c9/django/core/handlers/base.py#L334-L370","documentation":"Raised as a RuntimeError by BaseHandler.make_view_atomic when ATOMIC_REQUESTS is enabled on a database connection and the view being wrapped is a coroutine function (async def). Django cannot wrap an async view in transaction.atomic because the sync transaction wrapper would break the async execution model.","triggerScenarios":"Setting 'ATOMIC_REQUESTS': True in DATABASES for a connection and defining any 'async def' view that uses (or is routed through) that connection; enabling ATOMIC_REQUESTS globally then adding a single async view.","commonSituations":"Enabling ATOMIC_REQUESTS to get per-request transactions then adopting async views; copying a sync config to an async-capable project without adjusting the setting.","solutions":["Disable ATOMIC_REQUESTS in DATABASES, or set it to False for connections used by async views.","Mark async views with the 'transaction.non_atomic_requests' attribute so they are excluded: my_view.non_atomic_requests = {'default'} or use the decorator @transaction.non_atomic_requests.","Manage transactions manually inside the async view using 'async with transaction.atomic():'."],"exampleFix":"// before\n# settings.py\nDATABASES = {'default': {'ENGINE': ..., 'ATOMIC_REQUESTS': True}}\nasync def my_view(request): ...\n// after\nDATABASES = {'default': {'ENGINE': ..., 'ATOMIC_REQUESTS': False}}\n# or decorate the async view:\nfrom django.db import transaction\n@transaction.non_atomic_requests\nasync def my_view(request): ...","handlingStrategy":"validation","validationCode":"import asyncio, inspect\nfrom django.conf import settings\ndef check_async_views_atomic_conflict(view):\n    atomic = any(db.get('ATOMIC_REQUESTS') for db in settings.DATABASES.values())\n    if atomic and inspect.iscoroutinefunction(view):\n        raise RuntimeError('ATOMIC_REQUESTS conflicts with an async view')","typeGuard":"import inspect\nfrom django.db import transaction\ndef view_is_async_and_atomic(view) -> bool:\n    aliases = set(getattr(view, '_non_atomic_requests', set()))\n    return inspect.iscoroutinefunction(view) and not aliases","tryCatchPattern":null,"preventionTips":["Avoid ATOMIC_REQUESTS in projects that use async views.","Mark async views with @transaction.non_atomic_requests or set .non_atomic_requests.","Add a system check that flags async views when ATOMIC_REQUESTS is enabled."],"tags":["async","transactions","configuration","django"],"analyzedSha":"ae25a40be07e8a749edf526df37c93e59d4a22c9","analyzedAt":"2026-08-06T21:46:51.801Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}