diff --git a/skyvern/forge/sdk/workflow/models/block.py b/skyvern/forge/sdk/workflow/models/block.py index 95e0c9e8a..39a0d7a47 100644 --- a/skyvern/forge/sdk/workflow/models/block.py +++ b/skyvern/forge/sdk/workflow/models/block.py @@ -29,7 +29,7 @@ import pyotp import structlog from charset_normalizer import from_bytes from email_validator import EmailNotValidError, validate_email -from jinja2 import StrictUndefined, TemplateSyntaxError +from jinja2 import StrictUndefined, TemplateSyntaxError, UndefinedError from jinja2.sandbox import SandboxedEnvironment from opentelemetry import trace as otel_trace from playwright.async_api import Page @@ -803,12 +803,14 @@ class BaseTaskBlock(Block): formatted_error_code = self.format_block_parameter_template_from_workflow_run_context( error_code, workflow_run_context ) - except TemplateSyntaxError as exc: + except (TemplateSyntaxError, UndefinedError) as exc: + error_detail = exc.message if isinstance(exc, UndefinedError) else exc.message + error_location = "" if isinstance(exc, UndefinedError) else f" (line {exc.lineno})" raise FailedToFormatJinjaStyleParameter( template=error_code, msg=( - "Invalid Jinja syntax in error_code_mapping key " - f"'{error_code}': {exc.message} (line {exc.lineno})" + "Invalid Jinja template in error_code_mapping key " + f"'{error_code}': {error_detail}{error_location}" ), ) from exc @@ -816,12 +818,14 @@ class BaseTaskBlock(Block): formatted_error_description = self.format_block_parameter_template_from_workflow_run_context( error_description, workflow_run_context ) - except TemplateSyntaxError as exc: + except (TemplateSyntaxError, UndefinedError) as exc: + error_detail = exc.message if isinstance(exc, UndefinedError) else exc.message + error_location = "" if isinstance(exc, UndefinedError) else f" (line {exc.lineno})" raise FailedToFormatJinjaStyleParameter( template=error_description, msg=( - "Invalid Jinja syntax in error_code_mapping value for key " - f"'{error_code}': {exc.message} (line {exc.lineno})" + "Invalid Jinja template in error_code_mapping value for key " + f"'{error_code}': {error_detail}{error_location}" ), ) from exc diff --git a/tests/unit/test_task_block_error_code_mapping_template_errors.py b/tests/unit/test_task_block_error_code_mapping_template_errors.py index 6758acec5..51111a04d 100644 --- a/tests/unit/test_task_block_error_code_mapping_template_errors.py +++ b/tests/unit/test_task_block_error_code_mapping_template_errors.py @@ -2,8 +2,11 @@ from datetime import datetime, timezone from unittest.mock import MagicMock import pytest +from jinja2 import StrictUndefined +from jinja2.sandbox import SandboxedEnvironment from skyvern.forge.sdk.workflow.exceptions import FailedToFormatJinjaStyleParameter +from skyvern.forge.sdk.workflow.models import block as block_module from skyvern.forge.sdk.workflow.models.block import TaskBlock from skyvern.forge.sdk.workflow.models.parameter import OutputParameter, ParameterType @@ -79,3 +82,29 @@ def test_error_code_mapping_key_reports_precise_jinja_syntax_error() -> None: error_message = str(exc_info.value) assert "error_code_mapping key '{{ error code }}'" in error_message assert "expected token 'end of print statement'" in error_message + + +def test_error_code_mapping_value_reports_undefined_variable_in_strict_mode( + monkeypatch: pytest.MonkeyPatch, +) -> None: + strict_env = SandboxedEnvironment(undefined=StrictUndefined) + strict_env.filters["json"] = block_module._json_type_filter + monkeypatch.setattr(block_module, "jinja_sandbox_env", strict_env) + + block = TaskBlock( + label="block_1", + block_type="task", + title="Test block", + output_parameter=_build_output_parameter(), + error_code_mapping={ + "ACCOUNT_GROUP_NOT_FOUND": "return this error when {{ nonexistent_output }} is missing" + }, + ) + ctx = _build_mock_context() + + with pytest.raises(FailedToFormatJinjaStyleParameter) as exc_info: + block.format_potential_template_parameters(ctx) + + error_message = str(exc_info.value) + assert "error_code_mapping value for key 'ACCOUNT_GROUP_NOT_FOUND'" in error_message + assert "'nonexistent_output' is undefined" in error_message