pg_createsubscriber: Fix incorrect handling of cleanup flags — May 2026 Summary
Overview
A bug in pg_createsubscriber's cleanup flag handling was identified, reviewed, and committed (with backpatch to v17) during this month. The fix removes incorrect state mutations that could leave orphaned publications and replication slots on the primary server after failures.
The Bug
pg_createsubscriber converts a physical standby into a logical replication subscriber through a multi-step process. Two boolean flags (made_publication, made_replslot) in the per-database dbinfo structure gate cleanup of tool-created objects on the primary via an atexit handler.
The helper functions drop_publication() and drop_replication_slot() are reused for multiple purposes:
- Dropping tool-created objects on the primary during cleanup
- Dropping replicated/inherited publications on the subscriber
- Dropping user-requested publications (
--remove=publications) - Dropping physical replication slots and failover-synced slots
These functions unconditionally reset the cleanup flags on failure, regardless of which object or server was involved. If a subscriber-side drop failed, it would flip made_publication = false, causing the atexit handler to skip cleanup of the primary-side tool-created publication — leaving orphaned objects.
The Fix
The resolution was minimal: remove the made_publication = false and made_replslot = false assignments entirely from the drop functions. Rationale:
- The "don't retry" semantics these resets provided are pointless since
atexitcleanup is the final action before process termination - The worst case of leaving flags set is a duplicate error message — harmless
- The
atexithandler becomes the sole authority on cleanup decisions
Review and Commit Timeline
- Peter Smith questioned whether recent commits (
e5aeed4,85ddcc2) invalidated the patch - Nisha Moond defended the patch with detailed analysis: the flags are publisher-side cleanup flags, and resetting them due to subscriber-side failures is semantically incorrect regardless of recent changes. She confirmed commit
85ddcc2's new read ofmade_publication(for subscriber-side logic) is unaffected since the patch only removes the write (reset to false) - v5 patch submitted as a rebase with no logic changes
- Fujii Masao announced intent to commit and backpatch to v17
- Patch committed — thread concluded
Architectural Lesson
This is a textbook case of feature creep eroding invariants. drop_publication() originally existed solely to clean up tool-created publications (making the flag mutation sensible). As it was reused for subscriber-side drops and --remove operations, the original invariant silently broke. The fix shrinks the function's contract to match its actual multi-purpose usage rather than adding conditional logic.