From ce37d80fb5c80e5269a156cd845454bb998316cf Mon Sep 17 00:00:00 2001 From: Aegis Dev Date: Sun, 31 May 2026 18:41:29 -0400 Subject: [PATCH] fix(workflow): catch IndexError in _resolve_placeholders for positional format specifiers Strings containing positional format placeholders like {0} (e.g. from copy-pasted JSON values, URL templates, or CSS) caused an uncaught IndexError when str.format(**context) was called in _resolve_placeholders. Only KeyError was caught before; now both KeyError and IndexError are caught so the original string is returned unchanged instead of crashing the workflow. Fixes #154 --- workflows/tests/test_workflow_execution.py | 14 +++++++++++++- workflows/workflow_use/workflow/service.py | 9 ++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/workflows/tests/test_workflow_execution.py b/workflows/tests/test_workflow_execution.py index 472c645..00d4698 100644 --- a/workflows/tests/test_workflow_execution.py +++ b/workflows/tests/test_workflow_execution.py @@ -164,7 +164,19 @@ def test_semantic_strategies_format(self): assert 'xpath' not in strategy_types, 'Should not have xpath strategies' assert 'id' not in strategy_types, 'Should not have id strategies' - # Test 11: Actions requiring wait after execution + # Test 11: _resolve_placeholders does not raise on positional format specifiers + def test_resolve_placeholders_ignores_positional_format_specifiers(self): + """Test that strings with positional placeholders like {0} are returned unchanged instead of raising IndexError.""" + context = {'name': 'Alice'} + data = 'Input field value: {0}' + try: + if '{' in data and '}' in data: + result = data.format(**context) + except (KeyError, IndexError): + result = data + assert result == data, f'Expected original string unchanged, got {result!r}' + + # Test 12: Actions requiring wait after execution def test_actions_requiring_wait(self): """Test that certain actions trigger page stabilization wait""" # From line 189 of workflow_use/workflow/service.py diff --git a/workflows/workflow_use/workflow/service.py b/workflows/workflow_use/workflow/service.py index 1a6c325..56086ae 100644 --- a/workflows/workflow_use/workflow/service.py +++ b/workflows/workflow_use/workflow/service.py @@ -517,9 +517,12 @@ def _resolve_placeholders(self, data: Any) -> Any: formatted_data = data.format(**self.context) return formatted_data return data # No placeholders, return as is - except KeyError: - # A key in the placeholder was not found in the context. - # Return the original string as per previous behavior. + except (KeyError, IndexError): + # KeyError: a named placeholder key was not found in the context. + # IndexError: a positional placeholder like {0} was present but no + # positional args were supplied (e.g. copy-pasted JSON, URL templates, + # or CSS strings containing numeric format specifiers). + # In both cases, return the original string unchanged. return data # TODO: This next things are not really supported atm, we'll need to to do it in the future.