This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: pg17-subxact-spill-guardrails

PostgreSQL 17 Subtransaction Spill & Snapshot Invalidation Guardrails

Enforces strict structural constraints on nested savepoints, ORM nested transactions, and PL/pgSQL exception blocks to prevent backend subtransaction overflow beyond the 64-subxid PGPROC memory cache. Prevents ProcArrayLock contention storms, SLRU cache thrashing, and snapshot invalidation latency spikes under high-concurrency workloads.

Prohibited Anti-Pattern: Unbounded SAVEPOINT nesting and row-level try/catch exception loops overflowing backend PGPROC subxid caches

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: PostgreSQL 17 Subtransaction Spill & Snapshot Invalidation Guardrails - Enforces strict structural constraints on nested savepoints, ORM nested transactions, and PL/pgSQL exception blocks to prevent backend subtransaction overflow beyond the 64-subxid PGPROC memory cache. Prevents ProcArrayLock contention storms, SLRU cache thrashing, and snapshot invalidation latency spikes under high-concurrency workloads.
globs: src/**/*.ts, src/**/*.js, src/**/*.py, src/**/*.go, src/**/*.sql
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/pg17-subxact-spill-guardrails"
---

# PostgreSQL 17 Subtransaction Spill & Snapshot Invalidation Guardrails

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Unbounded SAVEPOINT nesting and row-level try/catch exception loops overflowing backend PGPROC subxid caches

## System Constraints
You are a Principal Software Architect enforcing PostgreSQL 17 Memory-Optimized Subtransaction Spill Guardrails. You must forbid code patterns that exceed the 64-subxid PGPROC cache limit or trigger the suboverflowed flag in backend workers. Mandate bulk primitives, ON CONFLICT idempotency, and decoupled transactional chunks over nested savepoints.

## Strict Guidelines
- Engineers MUST NOT execute per-iteration SAVEPOINT or nested transaction blocks within loops (e.g., ORM nested transactions, PL/pgSQL EXCEPTION blocks).
- Engineers MUST strictly cap nested transaction depth to at most 1 level per logical request to guarantee subxids never exceed the 64-slot in-memory PGPROC threshold.
- Code MUST replace exception-based optimistic concurrency or catch-and-retry loops inside transactions with atomic SQL primitives (e.g., INSERT ... ON CONFLICT DO NOTHING/UPDATE).
- Services handling high-concurrency batch ingestion MUST execute batch operations in bounded, standalone top-level transactions rather than wrapping thousands of entities in nested savepoints.
- Components NEVER rely on subtransaction rollbacks for business-logic control flow or error handling; failed operations must invalidate and abort the top-level transaction or execute out-of-transaction compensation.
- Database access layers MUST monitor and assert against subxid overflow telemetry via pg_stat_activity and lock monitoring views under peak connection load.

## Bad vs Good Implementations
### Loop-Level Savepoint Spill vs. Atomic Batch Upsert

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Creating savepoints inside a loop causes the transaction to exceed PostgreSQL's 64-subtransaction PGPROC cache. Once suboverflowed is set, all other concurrent transactions running snapshot lookups must take heavyweight locks and traverse pg_subtrans SLRU, creating catastrophic throughput collapse.
```typescript
import { PoolClient } from 'pg';

interface UserRecord {
  id: string;
  email: string;
  payload: Record<string, unknown>;
}

export async function bulkIngestUsersBad(client: PoolClient, users: UserRecord[]): Promise<void> {
  await client.query('BEGIN');
  try {
    for (let i = 0; i < users.length; i++) {
      const user = users[i];
      // ANTI-PATTERN: Emits >64 SAVEPOINTs in a single transaction.
      // Triggers suboverflowed = true in PGPROC, forcing every concurrent
      // backend to acquire ProcArrayLock and scan pg_subtrans SLRU buffers.
      await client.query(`SAVEPOINT sp_${i}`);
      try {
        await client.query(
          'INSERT INTO users (id, email, payload) VALUES ($1, $2, $3)',
          [user.id, user.email, JSON.stringify(user.payload)]
        );
        await client.query(`RELEASE SAVEPOINT sp_${i}`);
      } catch (err) {
        await client.query(`ROLLBACK TO SAVEPOINT sp_${i}`);
      }
    }
    await client.query('COMMIT');
  } catch (err) {
    await client.query('ROLLBACK');
    throw err;
  }
}
```

#### Production Standard (Correct)
> **Standard**: Replaces iterative nested savepoints with a single unnest batch upsert using ON CONFLICT. This generates zero subtransactions, keeps subxid count at zero, completely bypasses the subxid overflow condition, and maintains optimal PGPROC lockless visibility checks.
```typescript
import { PoolClient } from 'pg';

interface UserRecord {
  id: string;
  email: string;
  payload: Record<string, unknown>;
}

export async function bulkIngestUsersGood(client: PoolClient, users: UserRecord[]): Promise<void> {
  if (users.length === 0) return;

  // INVARIANT: Exactly 1 top-level transaction, 0 subtransactions.
  // Utilizes PostgreSQL ON CONFLICT for atomic idempotency without savepoints.
  await client.query('BEGIN');
  try {
    const ids: string[] = [];
    const emails: string[] = [];
    const payloads: string[] = [];

    for (const u of users) {
      ids.push(u.id);
      emails.push(u.email);
      payloads.push(JSON.stringify(u.payload));
    }

    const upsertQuery = `
      INSERT INTO users (id, email, payload)
      SELECT unnest($1::text[]), unnest($2::text[]), unnest($3::jsonb[])
      ON CONFLICT (id) DO UPDATE
      SET email = EXCLUDED.email,
          payload = EXCLUDED.payload;
    `;

    await client.query(upsertQuery, [ids, emails, payloads]);
    await client.query('COMMIT');
  } catch (err) {
    await client.query('ROLLBACK');
    throw err;
  }
}
```

Architectural Specification & Invariant Rationale

Architectural Invariant Design: PostgreSQL 17 Subtransaction Spill & Snapshot Invalidation Guardrails

PostgreSQL 17 Subtransaction Spill & Snapshot Invalidation Guardrails defines an industrial-grade behavioral standard for backend engineering. Enforces strict structural constraints on nested savepoints, ORM nested transactions, and PL/pgSQL exception blocks to prevent backend subtransaction overflow beyond the 64-subxid PGPROC memory cache. Prevents ProcArrayLock contention storms, SLRU cache thrashing, and snapshot invalidation latency spikes under high-concurrency 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: Unbounded SAVEPOINT nesting and row-level try/catch exception loops overflowing backend PGPROC subxid caches 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 DriftUnbounded SAVEPOINT nesting and row-level try/catch exception loops overflowing backend PGPROC subxid cachesCritical
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 NOT execute per-iteration SAVEPOINT or nested transaction blocks within loops (e.g., ORM nested transactions, PL/pgSQL EXCEPTION blocks).

Engineers MUST NOT execute per-iteration SAVEPOINT or nested transaction blocks within loops (e.g., ORM nested transactions, PL/pgSQL EXCEPTION blocks).

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 strictly cap nested transaction depth to at most 1 level per logical request to guarantee subxids never exceed the 64-slot in-memory PGPROC threshold.

Engineers MUST strictly cap nested transaction depth to at most 1 level per logical request to guarantee subxids never exceed the 64-slot in-memory PGPROC threshold.

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 MUST replace exception-based optimistic concurrency or catch-and-retry loops inside transactions with atomic SQL primitives (e.g., INSERT ... ON CONFLICT DO NOTHING/UPDATE).

Code MUST replace exception-based optimistic concurrency or catch-and-retry loops inside transactions with atomic SQL primitives (e.g., INSERT ... ON CONFLICT DO NOTHING/UPDATE).

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 handling high-concurrency batch ingestion MUST execute batch operations in bounded, standalone top-level transactions rather than wrapping thousands of entities in nested savepoints.

Services handling high-concurrency batch ingestion MUST execute batch operations in bounded, standalone top-level transactions rather than wrapping thousands of entities in nested savepoints.

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 rely on subtransaction rollbacks for business-logic control flow or error handling

Components NEVER rely on subtransaction rollbacks for business-logic control flow or error handling; failed operations must invalidate and abort the top-level transaction or execute out-of-transaction compensation.

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

Database access layers MUST monitor and assert against subxid overflow telemetry via pg_stat_activity and lock monitoring views under peak connection load.

Database access layers MUST monitor and assert against subxid overflow telemetry via pg_stat_activity and lock monitoring views under peak connection load.

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 PostgreSQL 17 Subtransaction Spill & Snapshot Invalidation Guardrails critical for AI coding assistants?

Enforces strict structural constraints on nested savepoints, ORM nested transactions, and PL/pgSQL exception blocks to prevent backend subtransaction overflow beyond the 64-subxid PGPROC memory cache. Prevents ProcArrayLock contention storms, SLRU cache thrashing, and snapshot invalidation latency spikes under high-concurrency 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 (Unbounded SAVEPOINT nesting and row-level try/catch exception loops overflowing backend PGPROC subxid caches) 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

PostgreSQL