This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: go124-weak-pointer-cache-finalizer-deadlock-prevention

Go 1.24 Weak Pointer Cache Eviction & Finalizer Deadlock Invariant

Enforces non-blocking weak reference tracking and decoupled cleanup semantics using Go 1.24 weak.Pointer and runtime.AddCleanup. Prohibits synchronous mutex acquisition in finalization routines and circular references that induce GC sweep latency spikes or permanent deadlock.

Prohibited Anti-Pattern: Lock Inversion and Object Resurrection via Synchronous Mutex Acquisition in GC Finalizers

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Go 1.24 Weak Pointer Cache Eviction & Finalizer Deadlock Invariant - Enforces non-blocking weak reference tracking and decoupled cleanup semantics using Go 1.24 weak.Pointer and runtime.AddCleanup. Prohibits synchronous mutex acquisition in finalization routines and circular references that induce GC sweep latency spikes or permanent deadlock.
globs: **/*.go
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/go124-weak-pointer-cache-finalizer-deadlock-prevention"
---

# Go 1.24 Weak Pointer Cache Eviction & Finalizer Deadlock Invariant

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Lock Inversion and Object Resurrection via Synchronous Mutex Acquisition in GC Finalizers

## System Constraints
You are a Principal Systems Architect enforcing Go 1.24 memory safety and GC concurrency invariants. You must mandate non-blocking weak reference lookups using `weak.Pointer[T]`, forbid synchronous locking within GC finalization callbacks (`runtime.AddCleanup` and `runtime.SetFinalizer`), and prevent cyclical references between cache control blocks and cached targets.

## Strict Guidelines
- Engineers MUST ALWAYS use Go 1.24 `weak.Pointer[T]` and `runtime.AddCleanup` instead of legacy `runtime.SetFinalizer` for weak-reference cache implementations.
- Engineers MUST NOT capture the target object or the cache container mutex inside a `runtime.AddCleanup` closure; pass only primitive keys or identifiers as closure arguments.
- Engineers MUST NOT acquire synchronous locks (`sync.Mutex`, `sync.RWMutex`) inside finalizer or cleanup execution paths; evictions MUST be dispatched asynchronously via non-blocking lock-free ring buffers or bounded channel notifications.
- Code MUST verify `weak.Pointer.Value()` is non-nil before use and immediately promote to a local strong pointer to avoid mid-operation GC reclamation.
- Services MUST implement tombstone or generational sweep passes to prune empty `weak.Pointer` references from the primary index rather than relying exclusively on GC-triggered cleanup callbacks.
- Components NEVER re-register cleanup hooks or resurrect dereferenced weak pointers when `Value()` returns nil.

## Bad vs Good Implementations
### Weak Cache Entry Reclamation and Deadlock-Free Cleanup

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Passing the Cache reference into runtime.AddCleanup and acquiring c.mu inside the cleanup callback creates an inverted lock dependency with the Go runtime memory allocator. If a thread holding c.mu attempts an allocation that triggers GC, the cleanup goroutine will block on c.mu, deadlocking the runtime.
```go
package cache

import (
	"runtime"
	"sync"
	"weak"
)

type Cache struct {
	mu    sync.RWMutex
	items map[string]weak.Pointer[Entry]
}

type Entry struct {
	Key   string
	Value []byte
}

func (c *Cache) Set(key string, val []byte) {
	c.mu.Lock()
	defer c.mu.Unlock()

	e := &Entry{Key: key, Value: val}
	c.items[key] = weak.Make(e)

	// DEADLOCK RISK: Synchronous lock acquisition inside cleanup.
	// Capturing *Cache and locking c.mu inside runtime.AddCleanup
	// deadlocks GC worker goroutines if an allocation triggers GC
	// while c.mu is held by another worker.
	runtime.AddCleanup(e, func(cRef *Cache) {
		cRef.mu.Lock()
		delete(cRef.items, key)
		cRef.mu.Unlock()
	}, c)
}
```

#### Production Standard (Correct)
> **Standard**: Decouples the GC cleanup lifecycle from the cache state machine. runtime.AddCleanup only captures the primitive key and enqueues to a buffered channel without acquiring locks. The worker goroutine independently acquires locks to clear nil entries, and Get promotes the weak pointer safely.
```go
package cache

import (
	"runtime"
	"sync"
	"weak"
)

type Cache struct {
	mu         sync.RWMutex
	items      map[string]weak.Pointer[Entry]
	evictQueue chan string
}

type Entry struct {
	Value []byte
}

func NewCache(bufferSize int) *Cache {
	c := &Cache{
		items:      make(map[string]weak.Pointer[Entry]),
		evictQueue: make(chan string, bufferSize),
	}
	go c.evictionWorker()
	return c
}

func (c *Cache) evictionWorker() {
	for key := range c.evictQueue {
		c.mu.Lock()
		if wp, exists := c.items[key]; exists {
			if wp.Value() == nil {
				delete(c.items, key)
			}
		}
		c.mu.Unlock()
	}
}

func (c *Cache) Set(key string, val []byte) *Entry {
	c.mu.Lock()
	defer c.mu.Unlock()

	e := &Entry{Value: val}
	c.items[key] = weak.Make(e)

	// Decoupled, non-blocking cleanup passing only primitive key
	runtime.AddCleanup(e, func(k string) {
		select {
		case c.evictQueue <- k:
		default:
			// Non-blocking drop: lazily cleared by Get or generational sweep
		}
	}, key)

	return e
}

func (c *Cache) Get(key string) (*Entry, bool) {
	c.mu.RLock()
	wp, exists := c.items[key]
	c.mu.RUnlock()
	if !exists {
		return nil, false
	}

	// Promote weak pointer to strong reference
	val := wp.Value()
	if val == nil {
		// Optional opportunistic lazy delete without blocking callers
		select {
		case c.evictQueue <- key:
		default:
		}
		return nil, false
	}
	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 Weak Pointer Cache Eviction & Finalizer Deadlock Invariant

Go 1.24 Weak Pointer Cache Eviction & Finalizer Deadlock Invariant defines an industrial-grade behavioral standard for backend engineering. Enforces non-blocking weak reference tracking and decoupled cleanup semantics using Go 1.24 weak.Pointer and runtime.AddCleanup. Prohibits synchronous mutex acquisition in finalization routines and circular references that induce GC sweep latency spikes or permanent deadlock. 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: Lock Inversion and Object Resurrection via Synchronous Mutex Acquisition in GC Finalizers 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 DriftLock Inversion and Object Resurrection via Synchronous Mutex Acquisition in GC FinalizersCritical
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 use Go 1.24 `weak.Pointer[T]` and `runtime.AddCleanup` instead of legacy `runtime.SetFinalizer` for weak-reference cache implementations.

Engineers MUST ALWAYS use Go 1.24 `weak.Pointer[T]` and `runtime.AddCleanup` instead of legacy `runtime.SetFinalizer` for weak-reference cache implementations.

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 capture the target object or the cache container mutex inside a `runtime.AddCleanup` closure

Engineers MUST NOT capture the target object or the cache container mutex inside a `runtime.AddCleanup` closure; pass only primitive keys or identifiers as closure arguments.

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 NOT acquire synchronous locks (`sync.Mutex`, `sync.RWMutex`) inside finalizer or cleanup execution paths

Engineers MUST NOT acquire synchronous locks (`sync.Mutex`, `sync.RWMutex`) inside finalizer or cleanup execution paths; evictions MUST be dispatched asynchronously via non-blocking lock-free ring buffers or bounded channel notifications.

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

Code MUST verify `weak.Pointer.Value()` is non-nil before use and immediately promote to a local strong pointer to avoid mid-operation GC reclamation.

Code MUST verify `weak.Pointer.Value()` is non-nil before use and immediately promote to a local strong pointer to avoid mid-operation GC reclamation.

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

Services MUST implement tombstone or generational sweep passes to prune empty `weak.Pointer` references from the primary index rather than relying exclusively on GC-triggered cleanup callbacks.

Services MUST implement tombstone or generational sweep passes to prune empty `weak.Pointer` references from the primary index rather than relying exclusively on GC-triggered cleanup callbacks.

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

Components NEVER re-register cleanup hooks or resurrect dereferenced weak pointers when `Value()` returns nil.

Components NEVER re-register cleanup hooks or resurrect dereferenced weak pointers when `Value()` returns nil.

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 Weak Pointer Cache Eviction & Finalizer Deadlock Invariant critical for AI coding assistants?

Enforces non-blocking weak reference tracking and decoupled cleanup semantics using Go 1.24 weak.Pointer and runtime.AddCleanup. Prohibits synchronous mutex acquisition in finalization routines and circular references that induce GC sweep latency spikes or permanent deadlock. 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 (Lock Inversion and Object Resurrection via Synchronous Mutex Acquisition in GC Finalizers) 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