From b13ad62155ce4163adbc85fa4c075c9249d64adf Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 06:40:39 +0000 Subject: [PATCH 1/2] fix(cdk): Handle TypeError in _literal_eval for nested set literals When ast.literal_eval() encounters a string like "{{'\''web'\''}, {'\''discover'\''}}" that resembles nested Python set literals, it raises TypeError: unhashable type: '\''set'\'' because sets cannot contain other sets. The existing except clause only caught (ValueError, SyntaxError) but not TypeError. This fix adds TypeError to the except clause so the string is returned as-is, matching the existing behavior for other unparseable literals. Resolves https://github.com/airbytehq/oncall/issues/11543 Co-Authored-By: bot_apk --- airbyte_cdk/sources/declarative/interpolation/jinja.py | 2 +- .../sources/declarative/interpolation/test_jinja.py | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/airbyte_cdk/sources/declarative/interpolation/jinja.py b/airbyte_cdk/sources/declarative/interpolation/jinja.py index 558ee0add..15ead0391 100644 --- a/airbyte_cdk/sources/declarative/interpolation/jinja.py +++ b/airbyte_cdk/sources/declarative/interpolation/jinja.py @@ -125,7 +125,7 @@ def eval( def _literal_eval(self, result: Optional[str], valid_types: Optional[Tuple[Type[Any]]]) -> Any: try: evaluated = ast.literal_eval(result) # type: ignore # literal_eval is able to handle None - except (ValueError, SyntaxError): + except (ValueError, SyntaxError, TypeError): return result if (not valid_types and not isinstance(evaluated, complex)) or ( valid_types and isinstance(evaluated, valid_types) diff --git a/unit_tests/sources/declarative/interpolation/test_jinja.py b/unit_tests/sources/declarative/interpolation/test_jinja.py index 330c938b0..c358fe4aa 100644 --- a/unit_tests/sources/declarative/interpolation/test_jinja.py +++ b/unit_tests/sources/declarative/interpolation/test_jinja.py @@ -345,6 +345,16 @@ def test_interpolation_private_partition_attribute(): assert actual_output == expected_output +def test_literal_eval_handles_unhashable_set_typeerror(): + """Test that _literal_eval gracefully handles TypeError from ast.literal_eval for nested sets.""" + # ast.literal_eval("{{'web'}, {'discover'}}") raises TypeError: unhashable type: 'set' + # The interpolation should return the string as-is instead of propagating the error. + config = {"query": "{{'web'}, {'discover'}}"} + s = "{{ config['query'] }}" + val = interpolation.eval(s, config) + assert val == "{{'web'}, {'discover'}}" + + def test_given_complex_when_eval_then_return_string(): s = "9173710294242221J" config = {} From 346cc58cae3cb453403ca477b95e7187d932f80d Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 21:51:34 +0000 Subject: [PATCH 2/2] fix: update inline comment per Copilot review suggestion Co-Authored-By: bot_apk --- airbyte_cdk/sources/declarative/interpolation/jinja.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/airbyte_cdk/sources/declarative/interpolation/jinja.py b/airbyte_cdk/sources/declarative/interpolation/jinja.py index 15ead0391..415a0c857 100644 --- a/airbyte_cdk/sources/declarative/interpolation/jinja.py +++ b/airbyte_cdk/sources/declarative/interpolation/jinja.py @@ -124,7 +124,7 @@ def eval( def _literal_eval(self, result: Optional[str], valid_types: Optional[Tuple[Type[Any]]]) -> Any: try: - evaluated = ast.literal_eval(result) # type: ignore # literal_eval is able to handle None + evaluated = ast.literal_eval(result) # type: ignore # result may be None; on error we return it unchanged except (ValueError, SyntaxError, TypeError): return result if (not valid_types and not isinstance(evaluated, complex)) or (