This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: fastapi-anyio-cancellation-scope-propagation-invariant

FastAPI AnyIO Native Cancellation Scope Exception Propagation Invariant

Guarantees deterministic task teardown and structured concurrency cleanup across asynchronous HTTP pipelines without leaking unawaited coroutines or swallowing cancellation signals. Enforces strict propagation of AnyIO cancellation exceptions and mandates shielded cancel scopes for non-negotiable cleanup operations.

Prohibited Anti-Pattern: Swallowing Cancellation Signals via Catch-All Handlers and Leaking Detached Coroutines

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: FastAPI AnyIO Native Cancellation Scope Exception Propagation Invariant - Guarantees deterministic task teardown and structured concurrency cleanup across asynchronous HTTP pipelines without leaking unawaited coroutines or swallowing cancellation signals. Enforces strict propagation of AnyIO cancellation exceptions and mandates shielded cancel scopes for non-negotiable cleanup operations.
globs: **/*.py, app/**/*.py, src/**/*.py
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/fastapi-anyio-cancellation-scope-propagation-invariant"
---

# FastAPI AnyIO Native Cancellation Scope Exception Propagation Invariant

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Swallowing Cancellation Signals via Catch-All Handlers and Leaking Detached Coroutines

## System Constraints
You are a Principal Software Architect enforcing deterministic structured concurrency in FastAPI microservices built on AnyIO. Your objective is to ensure asynchronous task lifecycles are strictly bounded to the active request scope, cancellation exceptions are never swallowed by broad exception handlers, and asynchronous teardown logic is properly shielded against premature termination.

## Strict Guidelines
- Engineers MUST ALWAYS allow `anyio.get_cancelled_exc_class()` (or `asyncio.CancelledError`) to propagate up the stack, never treating cancellation as a generic recoverable error.
- Engineers MUST NOT catch `BaseException` or use bare `except:` clauses without explicitly re-raising the active cancellation exception via `raise`.
- Engineers MUST ALWAYS wrap critical asynchronous rollback, session closure, and teardown logic in `with anyio.CancelScope(shield=True):` inside `finally` blocks to guarantee execution during client disconnects.
- Services MUST NEVER use raw `asyncio.create_task()` or `asyncio.ensure_future()` within route handlers for request-bound concurrency; use `anyio.create_task_group()` to enforce structured child-task hierarchies.
- Components NEVER suppress cancellation in custom middleware or dependency generators (`yield`), ensuring that context managers correctly tear down acquired resources when a client aborts the connection.

## Bad vs Good Implementations
### Structured Concurrency and Shielded Teardown vs. Swallowed Cancellation

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Using asyncio.create_task bypasses AnyIO's structured TaskGroup, creating unparented background tasks that leak memory when requests cancel. Catching broad exceptions can swallow cancellation tokens, and the unshielded 'await db.rollback()' in the finally block will immediately raise a CancelledError during client disconnect, leaving the database connection in a corrupted or unreleased state.
```python
import asyncio
from fastapi import APIRouter, Depends
from app.db import AsyncSession, get_db

router = APIRouter()

@router.post("/process-order")
async def process_order(payload: dict, db: AsyncSession = Depends(get_db)):
    try:
        # Anti-pattern: Detached concurrency breaks parent AnyIO cancel scope
        asyncio.create_task(db.audit_log(payload))
        await db.execute_long_transaction(payload)
    except Exception as exc:
        # Anti-pattern: Swallows BaseException derivatives or async cancellation in some runtimes
        # and fails to re-raise cancellation signals properly
        return {"status": "error", "message": str(exc)}
    finally:
        # Anti-pattern: Unshielded async cleanup will be aborted instantly if client disconnected
        await db.rollback()
```

#### Production Standard (Correct)
> **Standard**: Adheres to structured concurrency using anyio.create_task_group(), ensuring subtasks are cleanly cancelled if the main request is terminated. Catches and immediately re-raises AnyIO's cancellation exception class, preventing cancellation swallowing. Shields the critical rollback and session close operations in the finally block using a shielded CancelScope so cleanup completes deterministically even upon client disconnect.
```python
import anyio
from fastapi import APIRouter, Depends, HTTPException, status
from app.db import AsyncSession, get_db

router = APIRouter()

@router.post("/process-order")
async def process_order(payload: dict, db: AsyncSession = Depends(get_db)):
    cancelled_exc = anyio.get_cancelled_exc_class()
    try:
        async with anyio.create_task_group() as tg:
            tg.start_soon(db.audit_log, payload)
            await db.execute_long_transaction(payload)
    except cancelled_exc:
        # Invariant: Cancellation must propagate up Starlette/AnyIO middleware stack
        raise
    except Exception as exc:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Processing failed: {str(exc)}"
        ) from exc
    finally:
        # Invariant: Non-negotiable teardown must be shielded from active cancellation
        with anyio.CancelScope(shield=True):
            await db.rollback()
            await db.close()
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: FastAPI AnyIO Native Cancellation Scope Exception Propagation Invariant

FastAPI AnyIO Native Cancellation Scope Exception Propagation Invariant defines an industrial-grade behavioral standard for backend engineering. Guarantees deterministic task teardown and structured concurrency cleanup across asynchronous HTTP pipelines without leaking unawaited coroutines or swallowing cancellation signals. Enforces strict propagation of AnyIO cancellation exceptions and mandates shielded cancel scopes for non-negotiable cleanup operations. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Swallowing Cancellation Signals via Catch-All Handlers and Leaking Detached Coroutines Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftSwallowing Cancellation Signals via Catch-All Handlers and Leaking Detached CoroutinesCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST ALWAYS allow `anyio.get_cancelled_exc_class()` (or `asyncio.CancelledError`) to propagate up the stack, never treating cancellation as a generic recoverable error.

Engineers MUST ALWAYS allow `anyio.get_cancelled_exc_class()` (or `asyncio.CancelledError`) to propagate up the stack, never treating cancellation as a generic recoverable error.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NOT catch `BaseException` or use bare `except

Engineers MUST NOT catch `BaseException` or use bare `except:` clauses without explicitly re-raising the active cancellation exception via `raise`.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Engineers MUST ALWAYS wrap critical asynchronous rollback, session closure, and teardown logic in `with anyio.CancelScope(shield=True)

Engineers MUST ALWAYS wrap critical asynchronous rollback, session closure, and teardown logic in `with anyio.CancelScope(shield=True):` inside `finally` blocks to guarantee execution during client disconnects.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Services MUST NEVER use raw `asyncio.create_task()` or `asyncio.ensure_future()` within route handlers for request-bound concurrency

Services MUST NEVER use raw `asyncio.create_task()` or `asyncio.ensure_future()` within route handlers for request-bound concurrency; use `anyio.create_task_group()` to enforce structured child-task hierarchies.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Components NEVER suppress cancellation in custom middleware or dependency generators (`yield`), ensuring that context managers correctly tear down acquired resources when a client aborts the connection.

Components NEVER suppress cancellation in custom middleware or dependency generators (`yield`), ensuring that context managers correctly tear down acquired resources when a client aborts the connection.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is FastAPI AnyIO Native Cancellation Scope Exception Propagation Invariant critical for AI coding assistants?

Guarantees deterministic task teardown and structured concurrency cleanup across asynchronous HTTP pipelines without leaking unawaited coroutines or swallowing cancellation signals. Enforces strict propagation of AnyIO cancellation exceptions and mandates shielded cancel scopes for non-negotiable cleanup operations. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Swallowing Cancellation Signals via Catch-All Handlers and Leaking Detached Coroutines) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

1 Rule in Stack

FastAPI