This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: bun-websocket-kernel-drain-backpressure-invariant

Bun 1.2 Native WebSocket Kernel Drain and Backpressure Invariant

Enforces strict backpressure synchronization on Bun 1.2+ native WebSockets by monitoring kernel socket buffer write return values and hooking the native drain lifecycle event. Prevents silent heap exhaustion, uninhibited queue amplification, and process OOM crashes under gigabit-scale broadcast or streaming workloads.

Prohibited Anti-Pattern: Unchecked fire-and-forget ws.send() calls causing unbounded memory buffering during slow client drain

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Bun 1.2 Native WebSocket Kernel Drain and Backpressure Invariant - Enforces strict backpressure synchronization on Bun 1.2+ native WebSockets by monitoring kernel socket buffer write return values and hooking the native drain lifecycle event. Prevents silent heap exhaustion, uninhibited queue amplification, and process OOM crashes under gigabit-scale broadcast or streaming workloads.
globs: src/**/*.{ts,js}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/bun-websocket-kernel-drain-backpressure-invariant"
---

# Bun 1.2 Native WebSocket Kernel Drain and Backpressure Invariant

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Unchecked fire-and-forget ws.send() calls causing unbounded memory buffering during slow client drain

## System Constraints
You are a Principal Backend Systems Engineer enforcing zero-allocation and strict backpressure invariants on Bun 1.2 native WebSockets. Bun's `ws.send()` returns a number indicating byte write status: negative values for queue failure, zero for full kernel buffering, and positive values for immediate kernel transmission. You must enforce explicit backpressure handling, queue caps, and native `drain(ws)` callbacks across all WebSocket streaming paths to avoid silent V8/JavaScriptCore heap exhaustion.

## Strict Guidelines
- Engineers MUST ALWAYS evaluate the return value of `ws.send(data)`: if `ws.send()` returns 0 or negative, producers MUST pause transmissions to that client until the server's `drain(ws)` hook is triggered.
- Engineers MUST NEVER execute unbounded loops calling `ws.send()` without inspecting `ws.isBackpressured` or tracking per-socket buffered byte thresholds.
- Services MUST define a hard limit on in-memory queued chunks per client and aggressively terminate connections (`ws.close(1008, 'Policy Violation: Slow Consumer')`) when buffered byte limits exceed configured thresholds.
- Implementations MUST register a native `drain(ws)` handler in the `Bun.serve({ websocket: { drain(ws) { ... } } })` configuration to resume suspended streams, re-arm publishers, or drain application-layer ring buffers.
- Components NEVER store unsent binary or text frames in unbounded JavaScript heap arrays without backpressure bounds or evaporative shedding mechanisms.

## Bad vs Good Implementations
### Unbounded WebSocket Broadcast vs. Drain-Aware Bounded Queue

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: ws.send() returns a byte count or 0/negative status. Ignoring this return value creates an unbounded kernel/native heap queue when slow TCP clients fail to acknowledge ACK packets. In high-throughput systems, this triggers fatal silent SIGKILL OOM crashes.
```typescript
import { ServerWebSocket } from "bun";

// Anti-pattern: Blind fire-and-forget send; ignores return value and lacks drain handling
export function broadcastMetric(clients: Set<ServerWebSocket<unknown>>, payload: Uint8Array) {
  for (const ws of clients) {
    // Under gigabit load, slow consumers buffer infinitely in C++ heap until OOM kill
    ws.send(payload);
  }
}

Bun.serve({
  port: 3000,
  websocket: {
    message(ws, message) {},
    open(ws) {},
    close(ws) {}
    // Missing drain handler entirely
  },
  fetch(req, server) {
    if (server.upgrade(req)) return;
    return new Response("Upgrade failed", { status: 400 });
  }
});
```

#### Production Standard (Correct)
> **Standard**: Tracks native socket saturation through ws.send() return codes and ws.bufferedAmount, pauses immediate writes into an bounded FIFO queue, and uses the Bun websocket drain hook to flush pending data only when the native TCP socket buffer has evacuated.
```typescript
import { ServerWebSocket } from "bun";

interface ClientState {
  queue: Uint8Array[];
  backpressured: boolean;
}

const MAX_BUFFERED_BYTES = 1024 * 1024 * 4; // 4MB per-client ceiling

export function sendWithBackpressure(ws: ServerWebSocket<ClientState>, payload: Uint8Array): void {
  const state = ws.data;

  // Check native kernel buffer size via ws.bufferedAmount
  if (ws.bufferedAmount + payload.byteLength > MAX_BUFFERED_BYTES) {
    ws.close(1008, "Slow consumer: Buffer limit exceeded");
    return;
  }

  if (state.backpressured || state.queue.length > 0) {
    state.queue.push(payload);
    return;
  }

  const sentBytes = ws.send(payload);
  if (sentBytes <= 0) {
    // 0 = buffered natively, backpressure engaged; negative = write failure
    state.backpressured = true;
  }
}

Bun.serve<ClientState>({
  port: 3000,
  websocket: {
    open(ws) {
      ws.data = { queue: [], backpressured: false };
    },
    message(ws, message) {},
    drain(ws) {
      const state = ws.data;
      while (state.queue.length > 0) {
        const next = state.queue[0];
        const sent = ws.send(next);
        if (sent <= 0) {
          state.backpressured = true;
          return; // Still saturated, await next drain cycle
        }
        state.queue.shift();
      }
      state.backpressured = false;
    },
    close(ws) {
      ws.data.queue.length = 0;
    }
  },
  fetch(req, server) {
    if (server.upgrade(req, { data: { queue: [], backpressured: false } })) return;
    return new Response("Upgrade failed", { status: 400 });
  }
});
```

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 Native WebSocket Kernel Drain and Backpressure Invariant

Bun 1.2 Native WebSocket Kernel Drain and Backpressure Invariant defines an industrial-grade behavioral standard for backend engineering. Enforces strict backpressure synchronization on Bun 1.2+ native WebSockets by monitoring kernel socket buffer write return values and hooking the native drain lifecycle event. Prevents silent heap exhaustion, uninhibited queue amplification, and process OOM crashes under gigabit-scale broadcast or streaming workloads. 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: Unchecked fire-and-forget ws.send() calls causing unbounded memory buffering during slow client drain 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 DriftUnchecked fire-and-forget ws.send() calls causing unbounded memory buffering during slow client drainCritical
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 evaluate the return value of `ws.send(data)`

Engineers MUST ALWAYS evaluate the return value of `ws.send(data)`: if `ws.send()` returns 0 or negative, producers MUST pause transmissions to that client until the server's `drain(ws)` hook is triggered.

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 NEVER execute unbounded loops calling `ws.send()` without inspecting `ws.isBackpressured` or tracking per-socket buffered byte thresholds.

Engineers MUST NEVER execute unbounded loops calling `ws.send()` without inspecting `ws.isBackpressured` or tracking per-socket buffered byte thresholds.

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

Services MUST define a hard limit on in-memory queued chunks per client and aggressively terminate connections (`ws.close(1008, 'Policy Violation

Services MUST define a hard limit on in-memory queued chunks per client and aggressively terminate connections (`ws.close(1008, 'Policy Violation: Slow Consumer')`) when buffered byte limits exceed configured thresholds.

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

Implementations MUST register a native `drain(ws)` handler in the `Bun.serve({ websocket

Implementations MUST register a native `drain(ws)` handler in the `Bun.serve({ websocket: { drain(ws) { ... } } })` configuration to resume suspended streams, re-arm publishers, or drain application-layer ring buffers.

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 store unsent binary or text frames in unbounded JavaScript heap arrays without backpressure bounds or evaporative shedding mechanisms.

Components NEVER store unsent binary or text frames in unbounded JavaScript heap arrays without backpressure bounds or evaporative shedding mechanisms.

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 Native WebSocket Kernel Drain and Backpressure Invariant critical for AI coding assistants?

Enforces strict backpressure synchronization on Bun 1.2+ native WebSockets by monitoring kernel socket buffer write return values and hooking the native drain lifecycle event. Prevents silent heap exhaustion, uninhibited queue amplification, and process OOM crashes under gigabit-scale broadcast or streaming workloads. 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 (Unchecked fire-and-forget ws.send() calls causing unbounded memory buffering during slow client drain) 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