This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: go-iter-seq-deterministic-resource-teardown

Go 1.24 iter.Seq Deterministic Resource Teardown and Goroutine Leak Prevention

Enforces deterministic resource cleanup and goroutine leak prevention within Go 1.24 range-over-func push (`iter.Seq`, `iter.Seq2`) and pull (`iter.Pull`, `iter.Pull2`) iterators. Guarantees that when consumer loops break early, iterator yields halt immediately, `defer` blocks execute without truncation, and pull iterator `stop()` callbacks are registered to tear down producer goroutines.

Prohibited Anti-Pattern: Ignoring yield() False Returns and Omitting iter.Pull stop() Teardown, Causing Leaked Goroutines and Orphaned Handles

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Go 1.24 iter.Seq Deterministic Resource Teardown and Goroutine Leak Prevention - Enforces deterministic resource cleanup and goroutine leak prevention within Go 1.24 range-over-func push (`iter.Seq`, `iter.Seq2`) and pull (`iter.Pull`, `iter.Pull2`) iterators. Guarantees that when consumer loops break early, iterator yields halt immediately, `defer` blocks execute without truncation, and pull iterator `stop()` callbacks are registered to tear down producer goroutines.
globs: **/*.go
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/go-iter-seq-deterministic-resource-teardown"
---

# Go 1.24 iter.Seq Deterministic Resource Teardown and Goroutine Leak Prevention

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Ignoring yield() False Returns and Omitting iter.Pull stop() Teardown, Causing Leaked Goroutines and Orphaned Handles

## System Constraints
You are a Principal Go Systems Architect enforcing strict resource management and concurrency safety under Go 1.24 range-over-func iterators (`iter.Seq`, `iter.Seq2`). In push iterators, `yield(val)` returns `false` when a consumer executes `break`, `return`, or encounters a panic; the generator MUST abort iteration immediately to unwind its call stack and run `defer` cleanups. In pull iterators created via `iter.Pull` or `iter.Pull2`, the runtime launches a hidden producer goroutine; callers MUST deterministically invoke `defer stop()` to unblock the producer and release held resources. Flag any unhandled `yield` returns or missing `stop()` invocations as critical concurrency and leak vulnerabilities.

## Strict Guidelines
- Iterator producers MUST evaluate the boolean return value of `yield(...)` on every single invocation and immediately return from the generator when `false` is received.
- Iterator producers MUST place all resource cleanup (e.g., `rows.Close()`, `resp.Body.Close()`, `file.Close()`) inside `defer` statements prior to the first call to `yield`.
- Engineers converting push iterators to pull iterators via `iter.Pull` or `iter.Pull2` MUST invoke `defer stop()` immediately after obtaining the `next` and `stop` closures.
- Iterators consuming external channels, contexts, or streaming network connections MUST NOT silently drop cancellation signals or ignore context expiration while waiting to yield.
- Iterators MUST NEVER perform non-idempotent mutations or send across external channels after `yield()` has returned `false`.
- Code utilizing custom pull iterators across asynchronous boundaries MUST explicitly pass the `stop` function to cleanup routines if the consumer lifecycle escapes local scope.

## Bad vs Good Implementations
### Push Iterator: SQL Row Streaming with Immediate Exit and Defer Invariant

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: The iterator fails to check `yield(...)` return value. If the caller breaks out of `for u, err := range StreamUsers(db)` after finding the first match, the iterator continues querying all remaining rows. Furthermore, omitting `defer rows.Close()` before yielding causes an active connection leak when iteration terminates prematurely.
```go
package repository

import (
	"database/sql"
	"iter"
)

type User struct {
	ID   int64
	Name string
}

// ANTI-PATTERN: Ignores yield() return value and does not defer row closure.
// If consumer breaks early, rows leak, and unnecessary database reads continue.
func StreamUsers(db *sql.DB) iter.Seq2[User, error] {
	return func(yield func(User, error) bool) {
		rows, err := db.Query("SELECT id, name FROM users")
		if err != nil {
			yield(User{}, err)
			return
		}
		// Missing defer rows.Close()!
		for rows.Next() {
			var u User
			if err := rows.Scan(&u.ID, &u.Name); err != nil {
				yield(User{}, err)
				return
			}
			// Yield return value completely ignored!
			yield(u, nil)
		}
		rows.Close()
	}
}
```

#### Production Standard (Correct)
> **Standard**: By executing `defer rows.Close()` and verifying `if !yield(u, nil) { return }`, any early loop exit guarantees that the database cursor is cleanly closed and connection returned to the pool without scanning subsequent records.
```go
package repository

import (
	"database/sql"
	"iter"
)

type User struct {
	ID   int64
	Name string
}

// PRODUCTION STANDARD: yield() boolean is checked immediately;
// rows.Close() is registered via defer before iteration starts.
func StreamUsers(db *sql.DB) iter.Seq2[User, error] {
	return func(yield func(User, error) bool) {
		rows, err := db.Query("SELECT id, name FROM users")
		if err != nil {
			yield(User{}, err)
			return
		}
		defer rows.Close()

		for rows.Next() {
			var u User
			if err := rows.Scan(&u.ID, &u.Name); err != nil {
				yield(User{}, err)
				return
			}
			if !yield(u, nil) {
				// Consumer broke early (e.g., break, return, panic).
				// Halting immediately ensures defer rows.Close() runs deterministically.
				return
			}
		}

		if err := rows.Err(); err != nil {
			yield(User{}, err)
		}
	}
}
```

### Pull Iterator: Goroutine Lifetime Safety via iter.Pull Stop Guard

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: `iter.Pull` spins up a managed background goroutine that suspends and resumes via internal synchronization channels. When the loop returns early after finding a match without calling `stop()`, the goroutine remains permanently blocked waiting for the next pull or cleanup signal, causing a goroutine leak.
```go
package processor

import (
	"context"
	"iter"
)

// ANTI-PATTERN: Calls iter.Pull but fails to execute stop() on early exit,
// leaking the underlying runtime goroutine and any bound streaming resources.
func FindFirstMatch[T any](ctx context.Context, seq iter.Seq[T], matchFn func(T) bool) (T, bool) {
	next, _ := iter.Pull(seq) // Discards stop function!

	for {
		val, ok := next()
		if !ok {
			var zero T
			return zero, false
		}
		if matchFn(val) {
			return val, true // Leaks internal goroutine created by iter.Pull
		}
	}
}
```

#### Production Standard (Correct)
> **Standard**: Calling `defer stop()` ensures that whenever `FindFirstMatch` returns (whether via match found, channel closure, or context abort), the underlying goroutine spawned by `iter.Pull` is signaled to terminate and its local defer stacks are unwound.
```go
package processor

import (
	"context"
	"iter"
)

// PRODUCTION STANDARD: Registers defer stop() immediately upon invoking iter.Pull,
// guaranteeing the synthetic runtime goroutine terminates on all exit paths.
func FindFirstMatch[T any](ctx context.Context, seq iter.Seq[T], matchFn func(T) bool) (T, bool) {
	next, stop := iter.Pull(seq)
	defer stop()

	for {
		select {
		case <-ctx.Done():
			var zero T
			return zero, false
		default:
		}

		val, ok := next()
		if !ok {
			var zero T
			return zero, false
		}
		if matchFn(val) {
			return val, true
		}
	}
}
```

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 iter.Seq Deterministic Resource Teardown and Goroutine Leak Prevention

Go 1.24 iter.Seq Deterministic Resource Teardown and Goroutine Leak Prevention defines an industrial-grade behavioral standard for backend engineering. Enforces deterministic resource cleanup and goroutine leak prevention within Go 1.24 range-over-func push (`iter.Seq`, `iter.Seq2`) and pull (`iter.Pull`, `iter.Pull2`) iterators. Guarantees that when consumer loops break early, iterator yields halt immediately, `defer` blocks execute without truncation, and pull iterator `stop()` callbacks are registered to tear down producer goroutines. 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: Ignoring yield() False Returns and Omitting iter.Pull stop() Teardown, Causing Leaked Goroutines and Orphaned Handles 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 DriftIgnoring yield() False Returns and Omitting iter.Pull stop() Teardown, Causing Leaked Goroutines and Orphaned HandlesCritical
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

Iterator producers MUST evaluate the boolean return value of `yield(...)` on every single invocation and immediately return from the generator when `false` is received.

Iterator producers MUST evaluate the boolean return value of `yield(...)` on every single invocation and immediately return from the generator when `false` is received.

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

Iterator producers MUST place all resource cleanup (e.g., `rows.Close()`, `resp.Body.Close()`, `file.Close()`) inside `defer` statements prior to the first call to `yield`.

Iterator producers MUST place all resource cleanup (e.g., `rows.Close()`, `resp.Body.Close()`, `file.Close()`) inside `defer` statements prior to the first call to `yield`.

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 converting push iterators to pull iterators via `iter.Pull` or `iter.Pull2` MUST invoke `defer stop()` immediately after obtaining the `next` and `stop` closures.

Engineers converting push iterators to pull iterators via `iter.Pull` or `iter.Pull2` MUST invoke `defer stop()` immediately after obtaining the `next` and `stop` closures.

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

Iterators consuming external channels, contexts, or streaming network connections MUST NOT silently drop cancellation signals or ignore context expiration while waiting to yield.

Iterators consuming external channels, contexts, or streaming network connections MUST NOT silently drop cancellation signals or ignore context expiration while waiting to yield.

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

Iterators MUST NEVER perform non-idempotent mutations or send across external channels after `yield()` has returned `false`.

Iterators MUST NEVER perform non-idempotent mutations or send across external channels after `yield()` has returned `false`.

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.
6

Code utilizing custom pull iterators across asynchronous boundaries MUST explicitly pass the `stop` function to cleanup routines if the consumer lifecycle escapes local scope.

Code utilizing custom pull iterators across asynchronous boundaries MUST explicitly pass the `stop` function to cleanup routines if the consumer lifecycle escapes 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.
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 iter.Seq Deterministic Resource Teardown and Goroutine Leak Prevention critical for AI coding assistants?

Enforces deterministic resource cleanup and goroutine leak prevention within Go 1.24 range-over-func push (`iter.Seq`, `iter.Seq2`) and pull (`iter.Pull`, `iter.Pull2`) iterators. Guarantees that when consumer loops break early, iterator yields halt immediately, `defer` blocks execute without truncation, and pull iterator `stop()` callbacks are registered to tear down producer goroutines. 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 (Ignoring yield() False Returns and Omitting iter.Pull stop() Teardown, Causing Leaked Goroutines and Orphaned Handles) 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