This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: bun-asynclocalstorage-generator-propagation-contract

Bun 1.2 AsyncLocalStorage Context Preservation across Streaming Async Generators

Enforces deterministic trace context and ambient state propagation across native Bun asynchronous generators and ReadableStream response pipelines. Prevents silent context loss during event-loop interleaving and microtask detachment when yielding streaming chunks in high-throughput microservices. Mandates explicit context binding via AsyncLocalStorage.bind or captured execution contexts across async iterator consumption boundaries.

Prohibited Anti-Pattern: Unbound Async Generator Yielding Across Stream Consumers Causing Context Eviction

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Bun 1.2 AsyncLocalStorage Context Preservation across Streaming Async Generators - Enforces deterministic trace context and ambient state propagation across native Bun asynchronous generators and ReadableStream response pipelines. Prevents silent context loss during event-loop interleaving and microtask detachment when yielding streaming chunks in high-throughput microservices. Mandates explicit context binding via AsyncLocalStorage.bind or captured execution contexts across async iterator consumption boundaries.
globs: src/**/*.ts, src/services/**/*.ts, src/streaming/**/*.ts, src/http/**/*.ts
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/bun-asynclocalstorage-generator-propagation-contract"
---

# Bun 1.2 AsyncLocalStorage Context Preservation across Streaming Async Generators

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Unbound Async Generator Yielding Across Stream Consumers Causing Context Eviction

## System Constraints
You are a Principal Engineer enforcing the Bun 1.2 AsyncLocalStorage Generator Propagation Contract. In Bun microservices, passing raw asynchronous generators directly into streaming primitives (such as ReadableStream or native Response streaming) causes ambient execution context (trace IDs, span contexts, tenant metadata) to dissociate across asynchronous iteration steps. You must mandate strict context-binding boundaries using AsyncLocalStorage.bind, manual scope re-entry, or structured stream instrumentation to ensure zero trace-loss and prevent unhandled telemetry detachment.

## Strict Guidelines
- Engineers MUST ALWAYS bind asynchronous generator methods using `AsyncLocalStorage.bind()` or re-enter the active context within `.next()` loops when consumed across asynchronous stream boundaries.
- Engineers MUST NOT yield raw asynchronous generator instances directly into `new Response(stream)` or `ReadableStream.from()` without wrapping the chunk resolution within the origin context store.
- Code SHOULD enforce factory functions that encapsulate `als.run()` around long-lived stream pipelines rather than relying on ambient global propagation.
- Services MUST validate that distributed tracing IDs (e.g., OpenTelemetry span contexts) resolve non-null in every chunk generation iteration.
- Components NEVER expose unbounded `AsyncIterator` interfaces to HTTP response dispatchers without explicitly binding both generator construction and pull execution phases.

## Bad vs Good Implementations
### Context Loss in Streaming Response vs. Bound Generator Pipeline

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: In Bun 1.2, passing an unbound asynchronous iterator to ReadableStream.from() shifts consumption into the native stream pull loop. As chunks are resolved across event loop boundaries, the AsyncLocalStorage ambient context drops, returning undefined for getStore() inside intermediate yields and corrupted span records.
```typescript
import { AsyncLocalStorage } from 'node:async_hooks';

interface TraceContext {
  traceId: string;
  tenantId: string;
}

export const tracerStorage = new AsyncLocalStorage<TraceContext>();

// Anti-Pattern: The generator yields chunks across tick/stream boundaries.
// When consumed by Bun's native Response streaming, the ALS context is lost
// inside the generator loop or during external consumer consumption.
async function* generateDataStream(): AsyncGenerator<Uint8Array> {
  const encoder = new TextEncoder();
  for (let i = 0; i < 5; i++) {
    await Bun.sleep(10); // I/O context shift
    const ctx = tracerStorage.getStore(); // FAILS: ctx resolves to undefined in downstream ticks
    yield encoder.encode(`data: ${JSON.stringify({ index: i, traceId: ctx?.traceId })}\n\n`);
  }
}

export function handleStreamRequest(traceId: string, tenantId: string): Response {
  return tracerStorage.run({ traceId, tenantId }, () => {
    const generator = generateDataStream();
    // Returning directly into ReadableStream drops ALS propagation across native Bun runtime consumer iterations
    return new Response(ReadableStream.from(generator), {
      headers: { 'Content-Type': 'text/event-stream' },
    });
  });
}
```

#### Production Standard (Correct)
> **Standard**: The good pattern wraps the generator's protocol methods (.next, .return, .throw) with AsyncLocalStorage.bind(). This guarantees that regardless of which internal thread or event-loop microtask Bun uses to drive the ReadableStream consumption, execution re-enters the originating TraceContext deterministically.
```typescript
import { AsyncLocalStorage } from 'node:async_hooks';

interface TraceContext {
  traceId: string;
  tenantId: string;
}

export const tracerStorage = new AsyncLocalStorage<TraceContext>();

// Production Invariant: Context is bound explicitly to the iterator lifecycle
function bindAsyncGenerator<T, TReturn = void, TNext = unknown>(
  generator: AsyncGenerator<T, TReturn, TNext>,
  storage: AsyncLocalStorage<TraceContext>
): AsyncGenerator<T, TReturn, TNext> {
  const currentContext = storage.getStore();
  if (!currentContext) {
    throw new Error('Streaming execution initiated outside valid TraceContext');
  }

  return {
    [Symbol.asyncIterator]() {
      return this;
    },
    next: storage.bind((...args) => generator.next(...args)),
    return: storage.bind((...args) => generator.return(...args)),
    throw: storage.bind((...args) => generator.throw(...args)),
  } as AsyncGenerator<T, TReturn, TNext>;
}

async function* generateDataStream(): AsyncGenerator<Uint8Array> {
  const encoder = new TextEncoder();
  for (let i = 0; i < 5; i++) {
    await Bun.sleep(10);
    const ctx = tracerStorage.getStore();
    if (!ctx) throw new Error('TraceContext unexpectedly lost in bound generator tick');
    yield encoder.encode(`data: ${JSON.stringify({ index: i, traceId: ctx.traceId })}\n\n`);
  }
}

export function handleStreamRequest(traceId: string, tenantId: string): Response {
  return tracerStorage.run({ traceId, tenantId }, () => {
    const boundStream = bindAsyncGenerator(generateDataStream(), tracerStorage);
    
    return new Response(ReadableStream.from(boundStream), {
      headers: {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive',
      },
    });
  });
}
```

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: Bun 1.2 AsyncLocalStorage Context Preservation across Streaming Async Generators

Bun 1.2 AsyncLocalStorage Context Preservation across Streaming Async Generators defines an industrial-grade behavioral standard for backend engineering. Enforces deterministic trace context and ambient state propagation across native Bun asynchronous generators and ReadableStream response pipelines. Prevents silent context loss during event-loop interleaving and microtask detachment when yielding streaming chunks in high-throughput microservices. Mandates explicit context binding via AsyncLocalStorage.bind or captured execution contexts across async iterator consumption boundaries. 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: Unbound Async Generator Yielding Across Stream Consumers Causing Context Eviction 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 DriftUnbound Async Generator Yielding Across Stream Consumers Causing Context EvictionCritical
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 bind asynchronous generator methods using `AsyncLocalStorage.bind()` or re-enter the active context within `.next()` loops when consumed across asynchronous stream boundaries.

Engineers MUST ALWAYS bind asynchronous generator methods using `AsyncLocalStorage.bind()` or re-enter the active context within `.next()` loops when consumed across asynchronous stream boundaries.

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 yield raw asynchronous generator instances directly into `new Response(stream)` or `ReadableStream.from()` without wrapping the chunk resolution within the origin context store.

Engineers MUST NOT yield raw asynchronous generator instances directly into `new Response(stream)` or `ReadableStream.from()` without wrapping the chunk resolution within the origin context store.

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 SHOULD enforce factory functions that encapsulate `als.run()` around long-lived stream pipelines rather than relying on ambient global propagation.

Code SHOULD enforce factory functions that encapsulate `als.run()` around long-lived stream pipelines rather than relying on ambient global propagation.

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 validate that distributed tracing IDs (e.g., OpenTelemetry span contexts) resolve non-null in every chunk generation iteration.

Services MUST validate that distributed tracing IDs (e.g., OpenTelemetry span contexts) resolve non-null in every chunk generation iteration.

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 expose unbounded `AsyncIterator` interfaces to HTTP response dispatchers without explicitly binding both generator construction and pull execution phases.

Components NEVER expose unbounded `AsyncIterator` interfaces to HTTP response dispatchers without explicitly binding both generator construction and pull execution phases.

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 Bun 1.2 AsyncLocalStorage Context Preservation across Streaming Async Generators critical for AI coding assistants?

Enforces deterministic trace context and ambient state propagation across native Bun asynchronous generators and ReadableStream response pipelines. Prevents silent context loss during event-loop interleaving and microtask detachment when yielding streaming chunks in high-throughput microservices. Mandates explicit context binding via AsyncLocalStorage.bind or captured execution contexts across async iterator consumption boundaries. 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 (Unbound Async Generator Yielding Across Stream Consumers Causing Context Eviction) 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

Bun