From ae621ca5c0e87bc67e6aea61609f395ffdb0203a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 15 May 2026 01:41:28 +0000 Subject: [PATCH 1/4] Initial plan From 47866a3179c3387d19fcf8f14cc1ab052be71908 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 15 May 2026 01:47:36 +0000 Subject: [PATCH 2/4] Handle missing schedule job file as ValidationError Agent-Logs-Url: https://github.com/Azure/azure-sdk-for-python/sessions/366c4e6f-aa9c-4246-b4e2-db383393cc01 Co-authored-by: lavakumarrepala <221403938+lavakumarrepala@users.noreply.github.com> --- .../azure-ai-ml/azure/ai/ml/_schema/core/fields.py | 5 ++++- .../tests/schedule/unittests/test_schedule_entity.py | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/sdk/ml/azure-ai-ml/azure/ai/ml/_schema/core/fields.py b/sdk/ml/azure-ai-ml/azure/ai/ml/_schema/core/fields.py index fd7956b85bb0..28147fac2875 100644 --- a/sdk/ml/azure-ai-ml/azure/ai/ml/_schema/core/fields.py +++ b/sdk/ml/azure-ai-ml/azure/ai/ml/_schema/core/fields.py @@ -369,7 +369,10 @@ def _deserialize(self, value, attr, data, **kwargs): if not path.is_absolute(): path = base_path / path path.resolve() - data = load_file(path) + try: + data = load_file(path) + except (FileNotFoundError, OSError) as e: + raise ValidationError(f"No such file or directory: {path}") from e return data raise ValidationError(f"Not supporting non file for {attr}") diff --git a/sdk/ml/azure-ai-ml/tests/schedule/unittests/test_schedule_entity.py b/sdk/ml/azure-ai-ml/tests/schedule/unittests/test_schedule_entity.py index a4ea794ace51..2376f711817a 100644 --- a/sdk/ml/azure-ai-ml/tests/schedule/unittests/test_schedule_entity.py +++ b/sdk/ml/azure-ai-ml/tests/schedule/unittests/test_schedule_entity.py @@ -1,6 +1,7 @@ from datetime import datetime import pytest +from marshmallow import ValidationError from test_utilities.utils import verify_entity_load_and_dump from azure.ai.ml.constants import TimeZone @@ -189,3 +190,14 @@ def test_schedule_create_out_of_box_monitoring_job(self): test_path = "./tests/test_configs/schedule/out_of_box_monitoring.yaml" schedule = load_schedule(test_path) assert "genai_app_monitoring", schedule.name + + def test_load_schedule_with_nonexistent_pipeline_file_reference(self): + test_path = "./tests/test_configs/schedule/hello_cron_schedule_with_file_reference.yml" + params_override = [{"create_job.job": "../pipeline_jobs/not_exists_pipeline.yml"}] + + with pytest.raises(ValidationError) as e: + load_schedule(test_path, params_override=params_override) + + message = str(e.value) + assert "No such file or directory" in message + assert "In order to specify an existing jobs" not in message From 8198b91303182f1cadd4df750ca9796d17ec5293 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 15 May 2026 01:50:36 +0000 Subject: [PATCH 3/4] Short-circuit union errors for missing file references Agent-Logs-Url: https://github.com/Azure/azure-sdk-for-python/sessions/366c4e6f-aa9c-4246-b4e2-db383393cc01 Co-authored-by: lavakumarrepala <221403938+lavakumarrepala@users.noreply.github.com> --- .../azure/ai/ml/_schema/core/fields.py | 15 ++++++++++++++- .../schedule/unittests/test_schedule_entity.py | 3 ++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/sdk/ml/azure-ai-ml/azure/ai/ml/_schema/core/fields.py b/sdk/ml/azure-ai-ml/azure/ai/ml/_schema/core/fields.py index 28147fac2875..cd7c8390a3e3 100644 --- a/sdk/ml/azure-ai-ml/azure/ai/ml/_schema/core/fields.py +++ b/sdk/ml/azure-ai-ml/azure/ai/ml/_schema/core/fields.py @@ -454,6 +454,16 @@ def union_fields(self): def insert_union_field(self, field): self._union_fields.insert(0, field) + @staticmethod + def _contains_file_not_found_error(error_message): + if isinstance(error_message, str): + return "No such file or directory" in error_message + if isinstance(error_message, dict): + return any(UnionField._contains_file_not_found_error(value) for value in error_message.values()) + if isinstance(error_message, list): + return any(UnionField._contains_file_not_found_error(value) for value in error_message) + return False + # This sets the parent for the schema and also handles nesting. def _bind_to_schema(self, field_name, schema): super()._bind_to_schema(field_name, schema) @@ -487,7 +497,10 @@ def _deserialize(self, value, attr, data, **kwargs): try: return schema.deserialize(value, attr, data, **kwargs) except ValidationError as e: - errors.append(e.normalized_messages()) + normalized_messages = e.normalized_messages() + if self._contains_file_not_found_error(normalized_messages): + raise ValidationError(normalized_messages, field_name=attr) from e + errors.append(normalized_messages) except ValidationException as e: # ValidationException is explicitly raised in project code so usually easy to locate with error message errors.append([str(e)]) diff --git a/sdk/ml/azure-ai-ml/tests/schedule/unittests/test_schedule_entity.py b/sdk/ml/azure-ai-ml/tests/schedule/unittests/test_schedule_entity.py index 2376f711817a..ca813594ee06 100644 --- a/sdk/ml/azure-ai-ml/tests/schedule/unittests/test_schedule_entity.py +++ b/sdk/ml/azure-ai-ml/tests/schedule/unittests/test_schedule_entity.py @@ -200,4 +200,5 @@ def test_load_schedule_with_nonexistent_pipeline_file_reference(self): message = str(e.value) assert "No such file or directory" in message - assert "In order to specify an existing jobs" not in message + assert message.count("No such file or directory") == 1 + assert "Not supporting non file for create_job" not in message From ca194b55a4cc45f576f1bac71bb782604feb07ba Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 15 May 2026 01:51:41 +0000 Subject: [PATCH 4/4] Use shared file-not-found constant in schedule validation path Agent-Logs-Url: https://github.com/Azure/azure-sdk-for-python/sessions/366c4e6f-aa9c-4246-b4e2-db383393cc01 Co-authored-by: lavakumarrepala <221403938+lavakumarrepala@users.noreply.github.com> --- sdk/ml/azure-ai-ml/azure/ai/ml/_schema/core/fields.py | 5 +++-- .../tests/schedule/unittests/test_schedule_entity.py | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sdk/ml/azure-ai-ml/azure/ai/ml/_schema/core/fields.py b/sdk/ml/azure-ai-ml/azure/ai/ml/_schema/core/fields.py index cd7c8390a3e3..5986ab7d8f73 100644 --- a/sdk/ml/azure-ai-ml/azure/ai/ml/_schema/core/fields.py +++ b/sdk/ml/azure-ai-ml/azure/ai/ml/_schema/core/fields.py @@ -45,6 +45,7 @@ module_logger = logging.getLogger(__name__) T = typing.TypeVar("T") +NO_SUCH_FILE_OR_DIRECTORY_ERROR = "No such file or directory" class StringTransformedEnum(Field): @@ -372,7 +373,7 @@ def _deserialize(self, value, attr, data, **kwargs): try: data = load_file(path) except (FileNotFoundError, OSError) as e: - raise ValidationError(f"No such file or directory: {path}") from e + raise ValidationError(f"{NO_SUCH_FILE_OR_DIRECTORY_ERROR}: {path}") from e return data raise ValidationError(f"Not supporting non file for {attr}") @@ -457,7 +458,7 @@ def insert_union_field(self, field): @staticmethod def _contains_file_not_found_error(error_message): if isinstance(error_message, str): - return "No such file or directory" in error_message + return NO_SUCH_FILE_OR_DIRECTORY_ERROR in error_message if isinstance(error_message, dict): return any(UnionField._contains_file_not_found_error(value) for value in error_message.values()) if isinstance(error_message, list): diff --git a/sdk/ml/azure-ai-ml/tests/schedule/unittests/test_schedule_entity.py b/sdk/ml/azure-ai-ml/tests/schedule/unittests/test_schedule_entity.py index ca813594ee06..01b04b2f811c 100644 --- a/sdk/ml/azure-ai-ml/tests/schedule/unittests/test_schedule_entity.py +++ b/sdk/ml/azure-ai-ml/tests/schedule/unittests/test_schedule_entity.py @@ -4,6 +4,7 @@ from marshmallow import ValidationError from test_utilities.utils import verify_entity_load_and_dump +from azure.ai.ml._schema.core.fields import NO_SUCH_FILE_OR_DIRECTORY_ERROR from azure.ai.ml.constants import TimeZone from azure.ai.ml.entities import CronTrigger, JobSchedule, PipelineJob, RecurrencePattern, RecurrenceTrigger from azure.ai.ml.entities._load_functions import load_job, load_schedule @@ -199,6 +200,6 @@ def test_load_schedule_with_nonexistent_pipeline_file_reference(self): load_schedule(test_path, params_override=params_override) message = str(e.value) - assert "No such file or directory" in message - assert message.count("No such file or directory") == 1 + assert NO_SUCH_FILE_OR_DIRECTORY_ERROR in message + assert message.count(NO_SUCH_FILE_OR_DIRECTORY_ERROR) == 1 assert "Not supporting non file for create_job" not in message