This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: axum-tower-context-propagation-fence

Axum Tower Context Propagation Fence & Cancellation Isolation

Enforces deterministic task-local and OpenTelemetry span fencing across Axum Tower middleware pipelines. Prevents ambient context and tenant metadata contamination across multiplexed HTTP/2 streams and async cancellation boundaries by forbidding guard retention across `.await` points and enforcing explicit RAII span attachment.

Prohibited Anti-Pattern: Ambient Context and Tracing Span Leakage Across Async Dropped Futures and Thread Worker Pools

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Axum Tower Context Propagation Fence & Cancellation Isolation - Enforces deterministic task-local and OpenTelemetry span fencing across Axum Tower middleware pipelines. Prevents ambient context and tenant metadata contamination across multiplexed HTTP/2 streams and async cancellation boundaries by forbidding guard retention across `.await` points and enforcing explicit RAII span attachment.
globs: src/**/*.rs, crates/**/*.rs
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/axum-tower-context-propagation-fence"
---

# Axum Tower Context Propagation Fence & Cancellation Isolation

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Ambient Context and Tracing Span Leakage Across Async Dropped Futures and Thread Worker Pools

## System Constraints
You are a Principal Software Architect enforcing production-grade tracing isolation and tenant boundaries in Rust Axum and Tower applications. Async task cancellation in Tokio immediately drops pending futures at suspension points. If OpenTelemetry spans or tenant context rely on ambient thread-locals, manual guard management, or unattached task storage, cancelled or multiplexed requests will leak context into pooled worker threads or concurrent streams. Mandate strict fencing invariants across all Tower layers.

## Strict Guidelines
- Engineers MUST ALWAYS instrument response futures using `.instrument(span)` or `tracing::Instrument::instrument` rather than invoking `span.enter()` in async contexts.
- Engineers MUST NOT hold `tracing::span::Entered` guards across `.await` suspension points or inside pinned future closures, as Tokio task cancellation will orphan thread-local entered state.
- Code MUST isolate tenant metadata using request extensions (`http::Extensions`) or scoped task locals (`tokio::task_local!`) wrapped strictly with `task_local.scope(...)`.
- Services MUST extract parent OpenTelemetry W3C trace contexts directly into an explicit child span and attach that span directly to the inner `Service::call` future.
- Components NEVER use global static mutable thread-locals or unsynchronized ambient context stores to propagate identity or distributed tracing state across Tower layers.

## Bad vs Good Implementations
### Tower Middleware Context Attachment Under Cancellation

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Calling `span.enter()` synchronously within an async Tower service execution holds an ambient thread-local guard. When Tokio futures are cancelled or suspended across `.await` points, the span guard is not safely coordinated with task context switches, corrupting ambient traces and leaking tenant identity across requests multiplexed onto the same worker thread.
```rust
use axum::{extract::Request, response::Response};
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use tower::Service;
use tracing::info_span;

#[derive(Clone)]
pub struct TenantTelemetryService<S> {
    inner: S,
}

impl<S> Service<Request> for TenantTelemetryService<S>
where
    S: Service<Request, Response = Response> + Send + 'static,
    S::Future: Send + 'static,
{
    type Response = S::Response;
    type Error = S::Error;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;

    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.inner.poll_ready(cx)
    }

    fn call(&mut self, req: Request) -> Self::Future {
        let tenant_id = req.headers()
            .get("x-tenant-id")
            .and_then(|v| v.to_str().ok())
            .unwrap_or("unknown")
            .to_string();

        let span = info_span!("tenant_request", %tenant_id);
        // ANTI-PATTERN: `span.enter()` produces a synchronous Entered guard.
        // If the spawned/wrapped future is dropped during cancellation (e.g. client disconnect),
        // the guard's drop ordering can fail or leak into the underlying Tokio thread pool,
        // causing subsequent tasks scheduled on this thread to inherit the previous tenant's span.
        let _guard = span.enter();
        let fut = self.inner.call(req);

        Box::pin(async move {
            let res = fut.await?;
            Ok(res)
        })
    }
}
```

#### Production Standard (Correct)
> **Standard**: Using `tracing::Instrument::instrument` wraps the returned future in an `Instrumented` adapter. This adapter ensures the span is entered only during active polling and exited whenever the future yields or drops. Asynchronous task cancellation automatically drops the future safely without polluting the runtime thread or ambient tenant contexts.
```rust
use axum::{extract::Request, response::Response};
use std::task::{Context, Poll};
use tower::Service;
use tracing::{info_span, Instrument};

#[derive(Clone)]
pub struct TenantTelemetryService<S> {
    inner: S,
}

impl<S> Service<Request> for TenantTelemetryService<S>
where
    S: Service<Request, Response = Response> + Send + 'static,
    S::Future: Send + 'static,
{
    type Response = S::Response;
    type Error = S::Error;
    type Future = tracing::instrument::Instrumented<S::Future>;

    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.inner.poll_ready(cx)
    }

    fn call(&mut self, mut req: Request) -> Self::Future {
        let tenant_id = req.headers()
            .get("x-tenant-id")
            .and_then(|v| v.to_str().ok())
            .unwrap_or("unknown")
            .to_string();

        let span = info_span!(
            "tenant_request",
            %tenant_id,
            otel.name = "tenant_http_fence"
        );

        // Invariant: Securely isolate tenant identity inside request extensions
        req.extensions_mut().insert(tenant_id);

        // Invariant: Wrap the inner future using `.instrument()`.
        // Tracing's Instrumented future attaches and detaches the span deterministically
        // upon each poll and guarantees clean exit on premature drop/cancellation.
        self.inner.call(req).instrument(span)
    }
}
```

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Axum Tower Context Propagation Fence & Cancellation Isolation

Axum Tower Context Propagation Fence & Cancellation Isolation defines an industrial-grade behavioral standard for backend engineering. Enforces deterministic task-local and OpenTelemetry span fencing across Axum Tower middleware pipelines. Prevents ambient context and tenant metadata contamination across multiplexed HTTP/2 streams and async cancellation boundaries by forbidding guard retention across `.await` points and enforcing explicit RAII span attachment. 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: Ambient Context and Tracing Span Leakage Across Async Dropped Futures and Thread Worker Pools 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 DriftAmbient Context and Tracing Span Leakage Across Async Dropped Futures and Thread Worker PoolsCritical
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 instrument response futures using `.instrument(span)` or `tracing

Engineers MUST ALWAYS instrument response futures using `.instrument(span)` or `tracing::Instrument::instrument` rather than invoking `span.enter()` in async contexts.

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 hold `tracing

Engineers MUST NOT hold `tracing::span::Entered` guards across `.await` suspension points or inside pinned future closures, as Tokio task cancellation will orphan thread-local entered state.

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

Code MUST isolate tenant metadata using request extensions (`http

Code MUST isolate tenant metadata using request extensions (`http::Extensions`) or scoped task locals (`tokio::task_local!`) wrapped strictly with `task_local.scope(...)`.

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 extract parent OpenTelemetry W3C trace contexts directly into an explicit child span and attach that span directly to the inner `Service

Services MUST extract parent OpenTelemetry W3C trace contexts directly into an explicit child span and attach that span directly to the inner `Service::call` future.

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 use global static mutable thread-locals or unsynchronized ambient context stores to propagate identity or distributed tracing state across Tower layers.

Components NEVER use global static mutable thread-locals or unsynchronized ambient context stores to propagate identity or distributed tracing state across Tower layers.

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 Axum Tower Context Propagation Fence & Cancellation Isolation critical for AI coding assistants?

Enforces deterministic task-local and OpenTelemetry span fencing across Axum Tower middleware pipelines. Prevents ambient context and tenant metadata contamination across multiplexed HTTP/2 streams and async cancellation boundaries by forbidding guard retention across `.await` points and enforcing explicit RAII span attachment. 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 (Ambient Context and Tracing Span Leakage Across Async Dropped Futures and Thread Worker Pools) 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

Axum