Skip to content

contrib.blacksheep.register_tortoise breaks under ASGI: "No TortoiseContext is currently active" on every DB query (missing _enable_global_fallback=True) #2244

Description

@dgavrilov

Describe the bug

With Tortoise ORM 1.1.7, tortoise.contrib.blacksheep.register_tortoise sets up
the ORM in the app's on_start (ASGI lifespan) hook, but any DB query inside a
request handler
raises:

RuntimeError: No TortoiseContext is currently active. Use 'async with
TortoiseContext() as ctx:' to create one, or call Tortoise.init() for global state.

The lifespan hook runs in a different asyncio task than request handlers. Since
1.x stores connection state in a contextvars.ContextVar (_current_context),
the context entered during startup is not visible in handler tasks, and no global
fallback is set — so require_context() fails.

The FastAPI integration does not have this problem because
RegisterTortoise defaults _enable_global_fallback=True
(tortoise/contrib/fastapi/__init__.py, _enable_global_fallback: bool = True).
The blacksheep integration calls Tortoise.init(...) without that flag, so
the global fallback context described in tortoise/context.py (lines ~48-52) is
never enabled.

To Reproduce

import asyncio
from tortoise import Tortoise

CONFIG = {
    "connections": {"default": "sqlite://:memory:"},
    "apps": {"models": {"models": ["__main__"], "default_connection": "default"}},
}

from tortoise import fields, models
class User(models.Model):
    id = fields.IntField(pk=True)

async def run(enable_fallback: bool) -> str:
    async def init_task():
        await Tortoise.init(config=CONFIG, _enable_global_fallback=enable_fallback)
        await Tortoise.generate_schemas()
    await asyncio.create_task(init_task())          # like the lifespan task

    async def query_task():
        await User.all().count()                    # like a request handler
        return "ok"
    try:
        return await asyncio.create_task(query_task())
    except RuntimeError as exc:
        return f"RuntimeError: {exc}"
    finally:
        await Tortoise.close_connections()

async def main():
    print("without:", await run(False))
    print("with:   ", await run(True))

asyncio.run(main())

Output:

without: RuntimeError: No TortoiseContext is currently active. ...
with:    ok

A full repro with an actual BlackSheep app + register_tortoise shows the same
RuntimeError on the first request that touches the DB.

Expected behavior

register_tortoise should make the ORM usable from request handlers out of the
box, the same as the FastAPI integration.

Additional context

Pass _enable_global_fallback=True in the blacksheep integration's
Tortoise.init(...) call (matching contrib.fastapi.RegisterTortoise).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions