From 63c44878957196abfa124b17fe0ddae339e78f14 Mon Sep 17 00:00:00 2001
From: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Date: Wed, 7 Oct 2026 15:56:06 +0900
Subject: [PATCH v6 2/4] Avoid adding leader apply context to parallel worker
 errors

Errors from parallel apply workers are relayed through the leader apply
worker.  Before reporting such an error, ProcessParallelApplyMessage()
replaces error_context_stack with a stack saved by
LogicalRepApplyLoop().  This avoids running callbacks installed temporarily
by whatever the leader is doing when the error arrives.

Commit 216a784829c saved that stack after pushing apply_error_callback,
intentionally retaining the error context callbacks in effect inside
LogicalRepApplyLoop().  However, apply_error_callback describes the
leader's own apply state, including its current relation, remote transaction,
and replication message.  If the leader is applying another transaction
when a parallel worker reports an error, the callback therefore adds a
misleading CONTEXT line describing the leader's unrelated work.

The error relayed from the parallel worker already contains the context of
the operation that failed, so running the leader's apply_error_callback
provides no useful information.  Reverse this part of the choice made by
216a784829c by saving error_context_stack before pushing
apply_error_callback.  This preserves callbacks outside
LogicalRepApplyLoop() while excluding the leader's unrelated apply context.
---
 .../replication/logical/applyparallelworker.c       |  6 +++---
 src/backend/replication/logical/worker.c            | 13 ++++++++++---
 src/include/replication/worker_internal.h           |  2 +-
 3 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/src/backend/replication/logical/applyparallelworker.c b/src/backend/replication/logical/applyparallelworker.c
index 96bf499e49c..6a8b91df9d8 100644
--- a/src/backend/replication/logical/applyparallelworker.c
+++ b/src/backend/replication/logical/applyparallelworker.c
@@ -1046,10 +1046,10 @@ ProcessParallelApplyMessage(StringInfo msg)
 					edata.context = pstrdup(_("logical replication parallel apply worker"));
 
 				/*
-				 * Context beyond that should use the error context callbacks
-				 * that were in effect in LogicalRepApplyLoop().
+				 * Use the callbacks saved before the leader's apply error
+				 * context callback was installed.
 				 */
-				error_context_stack = apply_error_context_stack;
+				error_context_stack = apply_loop_outer_error_context_stack;
 
 				/*
 				 * The actual error must have been reported by the parallel
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 37b37500213..a1452686ef1 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -483,7 +483,12 @@ static ApplyRemoteCtx remote_ctx =
 	.origin_name = NULL,
 };
 
-ErrorContextCallback *apply_error_context_stack = NULL;
+/*
+ * Error context stack outside LogicalRepApplyLoop(), before
+ * apply_error_callback is pushed.  Used when the leader reports an error
+ * propagated from a parallel apply worker.
+ */
+ErrorContextCallback *apply_loop_outer_error_context_stack = NULL;
 
 MemoryContext ApplyMessageContext = NULL;
 MemoryContext ApplyContext = NULL;
@@ -4081,6 +4086,9 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
 	/* mark as idle, before starting to loop */
 	pgstat_report_activity(STATE_IDLE, NULL);
 
+	/* Preserve the error context stack outside the apply loop. */
+	apply_loop_outer_error_context_stack = error_context_stack;
+
 	/*
 	 * Push apply error context callback. Fields will be filled while applying
 	 * a change.
@@ -4088,7 +4096,6 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
 	errcallback.callback = apply_error_callback;
 	errcallback.previous = error_context_stack;
 	error_context_stack = &errcallback;
-	apply_error_context_stack = error_context_stack;
 
 	/* This outer loop iterates once per wait. */
 	for (;;)
@@ -4357,7 +4364,7 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
 
 	/* Pop the error context stack */
 	error_context_stack = errcallback.previous;
-	apply_error_context_stack = error_context_stack;
+	apply_loop_outer_error_context_stack = error_context_stack;
 
 	/* All done */
 	walrcv_endstreaming(LogRepWorkerWalRcvConn, &tli);
diff --git a/src/include/replication/worker_internal.h b/src/include/replication/worker_internal.h
index 88cb7c1e252..febe255c902 100644
--- a/src/include/replication/worker_internal.h
+++ b/src/include/replication/worker_internal.h
@@ -238,7 +238,7 @@ extern PGDLLIMPORT MemoryContext ApplyContext;
 
 extern PGDLLIMPORT MemoryContext ApplyMessageContext;
 
-extern PGDLLIMPORT ErrorContextCallback *apply_error_context_stack;
+extern PGDLLIMPORT ErrorContextCallback *apply_loop_outer_error_context_stack;
 
 extern PGDLLIMPORT ParallelApplyWorkerShared *MyParallelShared;
 
-- 
2.52.0

