From c6007d8909f2dee64a8fbd664aa97dd89f944884 Mon Sep 17 00:00:00 2001
From: Nitin Jadhav <nitinjadhavpostgres@gmail.com>
Date: Thu, 19 Feb 2026 08:28:34 +0000
Subject: [PATCH 1/2] Lower PANIC to FATAL for missing checkpoint error in
 no-backup_label path

Crash recovery without a backup_label currently PANICs if the checkpoint
record cannot be found.

Report this as FATAL instead, as missing WAL is a plausible operational
failure and the backup_label recovery path already treats it as a FATAL
error.
---
 src/backend/access/transam/xlogrecovery.c     |  2 +-
 ...pl => 050_missing_redo_no_backup_label.pl} |  0
 .../052_missing_checkpoint_no_backup_label.pl | 60 +++++++++++++++++++
 3 files changed, 61 insertions(+), 1 deletion(-)
 rename src/test/recovery/t/{050_redo_segment_missing.pl => 050_missing_redo_no_backup_label.pl} (100%)
 create mode 100644 src/test/recovery/t/052_missing_checkpoint_no_backup_label.pl

diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index c0c2744d45b..857dbb33f19 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -798,7 +798,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
 			 * can't read the last checkpoint because this allows us to
 			 * simplify processing around checkpoints.
 			 */
-			ereport(PANIC,
+			ereport(FATAL,
 					errmsg("could not locate a valid checkpoint record at %X/%08X",
 						   LSN_FORMAT_ARGS(CheckPointLoc)));
 		}
diff --git a/src/test/recovery/t/050_redo_segment_missing.pl b/src/test/recovery/t/050_missing_redo_no_backup_label.pl
similarity index 100%
rename from src/test/recovery/t/050_redo_segment_missing.pl
rename to src/test/recovery/t/050_missing_redo_no_backup_label.pl
diff --git a/src/test/recovery/t/052_missing_checkpoint_no_backup_label.pl b/src/test/recovery/t/052_missing_checkpoint_no_backup_label.pl
new file mode 100644
index 00000000000..1f2182f9f31
--- /dev/null
+++ b/src/test/recovery/t/052_missing_checkpoint_no_backup_label.pl
@@ -0,0 +1,60 @@
+# Copyright (c) 2025-2026, PostgreSQL Global Development Group
+#
+# Verify crash recovery behavior when the WAL segment containing the
+# checkpoint record referenced by pg_controldata is missing, in the code path
+# where there is no backup_label file.
+#
+# Expected behavior: startup fails with FATAL and logs a message about
+# not being able to locate a checkpoint record.
+
+use strict;
+use warnings FATAL => 'all';
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+my $node = PostgreSQL::Test::Cluster->new('testnode');
+$node->init;
+$node->append_conf('postgresql.conf', 'log_checkpoints = on');
+$node->start;
+
+# Force a checkpoint so pg_controldata points to a checkpoint record we can target.
+$node->safe_psql('postgres', 'CHECKPOINT;');
+
+# Retrieve the checkpoint LSN and derive the WAL segment name.
+my $checkpoint_lsn = $node->safe_psql('postgres',
+    "SELECT checkpoint_lsn FROM pg_control_checkpoint()");
+my $checkpoint_walfile =
+  $node->safe_psql('postgres', "SELECT pg_walfile_name('$checkpoint_lsn')");
+
+ok($checkpoint_walfile ne '', "derived checkpoint WAL file name: $checkpoint_walfile");
+
+# Stop the node.
+$node->stop('immediate');
+
+# Remove the WAL segment containing the checkpoint record.
+my $walpath = $node->data_dir . "/pg_wal/$checkpoint_walfile";
+ok(-f $walpath, "checkpoint WAL file exists before deletion: $walpath");
+
+unlink $walpath
+  or die "could not remove WAL file $walpath: $!";
+
+ok(!-e $walpath, "checkpoint WAL file removed: $walpath");
+
+# Use run_log instead of node->start because this test expects that
+# the server ends with an error during recovery.
+run_log(
+	[
+		'pg_ctl',
+		'--pgdata' => $node->data_dir,
+		'--log' => $node->logfile,
+		'start',
+	]);
+
+# Confirm that recovery has failed, as expected.
+my $logfile = slurp_file($node->logfile());
+ok( $logfile =~
+	  qr/FATAL: .* could not locate a valid checkpoint record at .*/,
+	"FATAL logged for missing checkpoint record (no backup_label path)");
+
+done_testing();
\ No newline at end of file
-- 
2.43.0

