This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: go124-chi-http3-quic-graceful-draining-guardrails

Go 1.24 Chi HTTP/3 QUIC Graceful Connection Draining and Migration Invariants

Mandates strict decoupling of UDP packet listener shutdown from active QUIC connection context lifecycles when serving HTTP/3 over Chi in Go 1.24. Precludes sudden socket termination by enforcing coordinated GOAWAY frame dissemination, bidirectional stream draining timeouts, and atomic connection closure without severing live client address migrations during rolling container deployments.

Prohibited Anti-Pattern: Premature UDP Packet Socket Closure and Abrupt QUIC Engine Termination Dropping In-Flight Multiplexed Streams

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Go 1.24 Chi HTTP/3 QUIC Graceful Connection Draining and Migration Invariants - Mandates strict decoupling of UDP packet listener shutdown from active QUIC connection context lifecycles when serving HTTP/3 over Chi in Go 1.24. Precludes sudden socket termination by enforcing coordinated GOAWAY frame dissemination, bidirectional stream draining timeouts, and atomic connection closure without severing live client address migrations during rolling container deployments.
globs: cmd/**/*.go, internal/**/*.go, pkg/**/*.go, **/server.go, **/main.go
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/go124-chi-http3-quic-graceful-draining-guardrails"
---

# Go 1.24 Chi HTTP/3 QUIC Graceful Connection Draining and Migration Invariants

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Premature UDP Packet Socket Closure and Abrupt QUIC Engine Termination Dropping In-Flight Multiplexed Streams

## System Constraints
You are a Principal Software Architect enforcing Go 1.24 Chi Graceful HTTP/3 QUIC Connection Migration and Draining Guardrails. Mandate strict socket lifecycle boundaries, preventing catastrophic stream termination during rolling deployments.

## Strict Guidelines
- Engineers MUST ALWAYS decouple the lifecycle of the underlying UDP net.PacketConn from the signal-handling parent context; never close the raw UDP socket before the HTTP/3 server has fully completed its draining phase.
- Engineers MUST ALWAYS initiate graceful HTTP/3 shutdowns via explicit GOAWAY frames (such as server.CloseGracefully with a bounded drain timeout) rather than ungraceful Close() calls that tear down state machines abruptly.
- Engineers MUST ensure the underlying UDP listener continues accepting datagrams during the draining window to service QUIC connection migration from roaming clients (e.g., Wi-Fi to cellular transitions).
- Services MUST synchronize both the Chi TCP (HTTP/1.1 & HTTP/2) and UDP (HTTP/3) listeners in lockstep using errgroup or coordinated sync primitives to prevent partial black-holing of dual-stack traffic.
- Components NEVER execute raw os.Exit() inside signal traps or termination callbacks before active bidirectional streams and long-lived QUIC control streams confirm completion or timeout expiration.

## Bad vs Good Implementations
### Dual-Stack Chi HTTP/3 Graceful Draining vs Abrupt Socket Termination

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Calling h3Server.Close() and immediately closing the UDP packet connection terminates in-flight multiplexed streams without sending graceful GOAWAY frames. It breaks QUIC client connection migration (e.g., cellular network transitions mid-request) because datagrams sent to new addresses are immediately rejected by the closed socket.
```go
package main

import (
	"context"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"github.com/go-chi/chi/v5"
	"github.com/quic-go/quic-go/http3"
)

func RunServer() {
	r := chi.NewRouter()
	r.Get("/data", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("payload"))
	})

	udpAddr, _ := net.ResolveUDPAddr("udp", ":443")
	pConn, _ := net.ListenUDP("udp", udpAddr)
	// ANTI-PATTERN: Direct defer close of packet conn terminates the socket
	// underneath active QUIC connection migration and mid-flight streams.
	defer pConn.Close()

	h3Server := &http3.Server{
		Handler: r,
		Addr:    ":443",
	}

	go func() {
		_ = h3Server.Serve(pConn)
	}()

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
	<-sig

	// ANTI-PATTERN: Calling Close() broadcasts immediate CONNECTION_CLOSE frames
	// with an error or closes the socket without allowing in-flight streams to finish.
	_ = h3Server.Close()
}
```

#### Production Standard (Correct)
> **Standard**: Decouples the net.PacketConn lifecycle from premature shutdown signals. CloseGracefully transmits HTTP/3 GOAWAY frames, bounds in-flight drain time via a 30-second context, keeps the UDP socket alive to ingest in-flight packets and route connection migration updates, and tears down the raw UDP listener only after the engine has drained.
```go
package main

import (
	"context"
	"errors"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
	"github.com/go-chi/chi/v5"
	"github.com/quic-go/quic-go/http3"
	"golang.org/x/sync/errgroup"
)

func RunServer() error {
	ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
	defer stop()

	r := chi.NewRouter()
	r.Get("/data", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("payload"))
	})

	udpAddr, err := net.ResolveUDPAddr("udp", ":443")
	if err != nil {
		return err
	}
	pConn, err := net.ListenUDP("udp", udpAddr)
	if err != nil {
		return err
	}

	h3Server := &http3.Server{
		Handler: r,
		Addr:    ":443",
	}

	g, gCtx := errgroup.WithContext(ctx)

	g.Go(func() error {
		err := h3Server.Serve(pConn)
		if errors.Is(err, http.ErrServerClosed) || errors.Is(err, net.ErrClosed) {
			return nil
		}
		return err
	})

	// Await termination signal
	<-gCtx.Done()

	// PHASE 1: Emit GOAWAY to reject new streams while maintaining UDP socket.
	// Drain in-flight bidirectional streams and allow connection migration packets to arrive.
	drainCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	drainErr := h3Server.CloseGracefully(drainCtx.Done())

	// PHASE 2: Close packet connection ONLY after active QUIC streams drain or timeout expires.
	socketErr := pConn.Close()

	serverErr := g.Wait()
	return errors.Join(drainErr, socketErr, serverErr)
}
```

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: Go 1.24 Chi HTTP/3 QUIC Graceful Connection Draining and Migration Invariants

Go 1.24 Chi HTTP/3 QUIC Graceful Connection Draining and Migration Invariants defines an industrial-grade behavioral standard for backend engineering. Mandates strict decoupling of UDP packet listener shutdown from active QUIC connection context lifecycles when serving HTTP/3 over Chi in Go 1.24. Precludes sudden socket termination by enforcing coordinated GOAWAY frame dissemination, bidirectional stream draining timeouts, and atomic connection closure without severing live client address migrations during rolling container deployments. 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: Premature UDP Packet Socket Closure and Abrupt QUIC Engine Termination Dropping In-Flight Multiplexed Streams 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 DriftPremature UDP Packet Socket Closure and Abrupt QUIC Engine Termination Dropping In-Flight Multiplexed StreamsCritical
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 decouple the lifecycle of the underlying UDP net.PacketConn from the signal-handling parent context

Engineers MUST ALWAYS decouple the lifecycle of the underlying UDP net.PacketConn from the signal-handling parent context; never close the raw UDP socket before the HTTP/3 server has fully completed its draining phase.

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 ALWAYS initiate graceful HTTP/3 shutdowns via explicit GOAWAY frames (such as server.CloseGracefully with a bounded drain timeout) rather than ungraceful Close() calls that tear down state machines abruptly.

Engineers MUST ALWAYS initiate graceful HTTP/3 shutdowns via explicit GOAWAY frames (such as server.CloseGracefully with a bounded drain timeout) rather than ungraceful Close() calls that tear down state machines abruptly.

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 ensure the underlying UDP listener continues accepting datagrams during the draining window to service QUIC connection migration from roaming clients (e.g., Wi-Fi to cellular transitions).

Engineers MUST ensure the underlying UDP listener continues accepting datagrams during the draining window to service QUIC connection migration from roaming clients (e.g., Wi-Fi to cellular transitions).

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 synchronize both the Chi TCP (HTTP/1.1 & HTTP/2) and UDP (HTTP/3) listeners in lockstep using errgroup or coordinated sync primitives to prevent partial black-holing of dual-stack traffic.

Services MUST synchronize both the Chi TCP (HTTP/1.1 & HTTP/2) and UDP (HTTP/3) listeners in lockstep using errgroup or coordinated sync primitives to prevent partial black-holing of dual-stack traffic.

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 execute raw os.Exit() inside signal traps or termination callbacks before active bidirectional streams and long-lived QUIC control streams confirm completion or timeout expiration.

Components NEVER execute raw os.Exit() inside signal traps or termination callbacks before active bidirectional streams and long-lived QUIC control streams confirm completion or timeout expiration.

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 Go 1.24 Chi HTTP/3 QUIC Graceful Connection Draining and Migration Invariants critical for AI coding assistants?

Mandates strict decoupling of UDP packet listener shutdown from active QUIC connection context lifecycles when serving HTTP/3 over Chi in Go 1.24. Precludes sudden socket termination by enforcing coordinated GOAWAY frame dissemination, bidirectional stream draining timeouts, and atomic connection closure without severing live client address migrations during rolling container deployments. 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 (Premature UDP Packet Socket Closure and Abrupt QUIC Engine Termination Dropping In-Flight Multiplexed Streams) 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

Go