From dfd2814e84d0c04845ba0649a9a7a7b476ee456a Mon Sep 17 00:00:00 2001
From: bramhanandlingala <bramhanand.lingala11@gmail.com>
Date: Sat, 25 Jul 2026 17:22:25 +0530
Subject: [PATCH] Fix template-field validation timing in PapermillOperator

---
 .../providers/papermill/operators/papermill.py      |  8 ++++----
 .../unit/papermill/operators/test_papermill.py      | 13 ++++++++++---
 .../ci/prek/validate_operators_init_exemptions.txt  |  1 -
 3 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/providers/papermill/src/airflow/providers/papermill/operators/papermill.py b/providers/papermill/src/airflow/providers/papermill/operators/papermill.py
index f41240ab26387..f0ce1607afd9b 100644
--- a/providers/papermill/src/airflow/providers/papermill/operators/papermill.py
+++ b/providers/papermill/src/airflow/providers/papermill/operators/papermill.py
@@ -89,12 +89,8 @@ def __init__(
         super().__init__(**kwargs)
         self.parameters = parameters
 
-        if not input_nb:
-            raise ValueError("Input notebook is not specified")
         self.input_nb = input_nb
 
-        if not output_nb:
-            raise ValueError("Output notebook is not specified")
         self.output_nb = output_nb
 
         self.kernel_name = kernel_name
@@ -105,6 +101,10 @@ def __init__(
         self.nbconvert_args = nbconvert_args
 
     def execute(self, context: Context):
+        if not self.input_nb:
+            raise ValueError("Input notebook is not specified")
+        if not self.output_nb:
+            raise ValueError("Output notebook is not specified")
         if not isinstance(self.input_nb, NoteBook):
             self.input_nb = NoteBook(url=self.input_nb, parameters=self.parameters)
         if not isinstance(self.output_nb, NoteBook):
diff --git a/providers/papermill/tests/unit/papermill/operators/test_papermill.py b/providers/papermill/tests/unit/papermill/operators/test_papermill.py
index f911fb8365843..b18c9e840238e 100644
--- a/providers/papermill/tests/unit/papermill/operators/test_papermill.py
+++ b/providers/papermill/tests/unit/papermill/operators/test_papermill.py
@@ -42,13 +42,20 @@ def test_templated_fields(self):
 class TestPapermillOperator:
     """Test PapermillOperator."""
 
+    def test_init_does_not_validate_notebooks(self):
+        """__init__ must not validate template fields; input_nb/output_nb are rendered after construction."""
+        op = PapermillOperator(task_id="missing_input_nb", output_nb="foo-bar")
+        assert op.input_nb is None
+        op = PapermillOperator(task_id="missing_output_nb", input_nb="foo-bar")
+        assert op.output_nb is None
+
     def test_mandatory_attributes(self):
-        """Test missing Input or Output notebooks."""
+        """Test missing Input or Output notebooks are validated at execute() time, after templating."""
         with pytest.raises(ValueError, match="Input notebook is not specified"):
-            PapermillOperator(task_id="missing_input_nb", output_nb="foo-bar")
+            PapermillOperator(task_id="missing_input_nb", output_nb="foo-bar").execute(context={})
 
         with pytest.raises(ValueError, match="Output notebook is not specified"):
-            PapermillOperator(task_id="missing_input_nb", input_nb="foo-bar")
+            PapermillOperator(task_id="missing_output_nb", input_nb="foo-bar").execute(context={})
 
     @pytest.mark.parametrize(
         ("output_nb_url", "output_as_object"),
diff --git a/scripts/ci/prek/validate_operators_init_exemptions.txt b/scripts/ci/prek/validate_operators_init_exemptions.txt
index 29ee3dd263922..16afe1fe88e8c 100644
--- a/scripts/ci/prek/validate_operators_init_exemptions.txt
+++ b/scripts/ci/prek/validate_operators_init_exemptions.txt
@@ -55,7 +55,6 @@ providers/microsoft/azure/src/airflow/providers/microsoft/azure/transfers/gcs_to
 providers/microsoft/azure/src/airflow/providers/microsoft/azure/transfers/oracle_to_azure_data_lake.py::OracleToAzureDataLakeOperator
 providers/microsoft/psrp/src/airflow/providers/microsoft/psrp/operators/psrp.py::PsrpOperator
 providers/oracle/src/airflow/providers/oracle/transfers/oracle_to_oracle.py::OracleToOracleOperator
-providers/papermill/src/airflow/providers/papermill/operators/papermill.py::PapermillOperator
 providers/standard/src/airflow/providers/standard/operators/bash.py::BashOperator
 providers/standard/src/airflow/providers/standard/operators/trigger_dagrun.py::TriggerDagRunOperator
 providers/standard/src/airflow/providers/standard/sensors/date_time.py::DateTimeSensor
