[Workflow] Fix: Wrap UndefinedError for error code mapping templates

Address review feedback by handling UndefinedError alongside
TemplateSyntaxError when rendering error_code_mapping keys and values.

- Catch UndefinedError and wrap in FailedToFormatJinjaStyleParameter
- Keep contextual key/value error messaging
- Add strict-mode unit test for undefined variable in mapping value
This commit is contained in:
LawyZheng 2026-04-24 21:05:51 +08:00
parent 13d71dd7e0
commit 09bd8b28ac
2 changed files with 40 additions and 7 deletions

View file

@ -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

View file

@ -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