From d99a964a4477a9bd58e7b6136186fccfd91801f3 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 26 Nov 2025 06:05:34 +0000 Subject: [PATCH 1/3] fix(low-code): handle all ScannerError exceptions in ConfigComponentsResolver Previously, the _parse_yaml_if_possible method only caught ScannerError exceptions containing '%' characters, but re-raised other ScannerError types. This caused failures when strings containing tab characters were passed through the YAML parser, as tabs cannot start tokens in YAML. This fix catches all ScannerError exceptions and returns the original value unchanged, which is the expected behavior for strings that are not valid YAML. Fixes: https://github.com/airbytehq/oncall/issues/10280 Co-Authored-By: unknown <> --- .../resolvers/config_components_resolver.py | 6 ++---- .../test_config_components_resolver.py | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/airbyte_cdk/sources/declarative/resolvers/config_components_resolver.py b/airbyte_cdk/sources/declarative/resolvers/config_components_resolver.py index 949b987db..de0fbf465 100644 --- a/airbyte_cdk/sources/declarative/resolvers/config_components_resolver.py +++ b/airbyte_cdk/sources/declarative/resolvers/config_components_resolver.py @@ -204,8 +204,6 @@ def _parse_yaml_if_possible(value: Any) -> Any: return yaml.safe_load(value) except ParserError: # "{{ record[0] in ['cohortActiveUsers'] }}" # not valid YAML return value - except ScannerError as e: # "%Y-%m-%d' # not valid yaml - if "expected alphabetic or numeric character, but found '%'" in str(e): - return value - raise e + except ScannerError: # "%Y-%m-%d" or strings with tabs - not valid YAML + return value return value diff --git a/unit_tests/sources/declarative/resolvers/test_config_components_resolver.py b/unit_tests/sources/declarative/resolvers/test_config_components_resolver.py index 988f27643..e957c8897 100644 --- a/unit_tests/sources/declarative/resolvers/test_config_components_resolver.py +++ b/unit_tests/sources/declarative/resolvers/test_config_components_resolver.py @@ -160,6 +160,20 @@ def to_configured_catalog( } ) +# Manifest with component definition with value containing tab characters +# which would cause YAML ScannerError (tabs cannot start tokens in YAML) +_MANIFEST_WITH_TAB_SCANNER_ERROR = deepcopy(_MANIFEST) +_MANIFEST_WITH_TAB_SCANNER_ERROR["dynamic_streams"][0]["components_resolver"][ + "components_mapping" +].append( + { + "type": "ComponentMappingDefinition", + "create_or_update": True, + "field_path": ["retriever", "requester", "$parameters", "custom_query"], + "value": "SELECT\n\tcampaign.name,\n\tcampaign.id\nFROM campaign", # Contains tab characters + } +) + @pytest.mark.parametrize( "manifest, config, expected_exception, expected_stream_names", @@ -173,8 +187,9 @@ def to_configured_catalog( ), (_MANIFEST_WITH_STREAM_CONFIGS_LIST, _CONFIG, None, ["item_1", "item_2", "default_item"]), (_MANIFEST_WITH_SCANNER_ERROR, _CONFIG, None, ["item_1", "item_2", "default_item"]), + (_MANIFEST_WITH_TAB_SCANNER_ERROR, _CONFIG, None, ["item_1", "item_2", "default_item"]), ], - ids=["no_duplicates", "duplicates", "stream_configs_list", "scanner_error"], + ids=["no_duplicates", "duplicates", "stream_configs_list", "scanner_error", "tab_scanner_error"], ) def test_dynamic_streams_read_with_config_components_resolver( manifest, config, expected_exception, expected_stream_names From 22e9d85c5adeeef333911a676b59ea701439f8d2 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 26 Nov 2025 06:06:53 +0000 Subject: [PATCH 2/3] style: apply ruff formatting to test file Co-Authored-By: unknown <> --- .../resolvers/test_config_components_resolver.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/unit_tests/sources/declarative/resolvers/test_config_components_resolver.py b/unit_tests/sources/declarative/resolvers/test_config_components_resolver.py index e957c8897..2e5f6ceac 100644 --- a/unit_tests/sources/declarative/resolvers/test_config_components_resolver.py +++ b/unit_tests/sources/declarative/resolvers/test_config_components_resolver.py @@ -189,7 +189,13 @@ def to_configured_catalog( (_MANIFEST_WITH_SCANNER_ERROR, _CONFIG, None, ["item_1", "item_2", "default_item"]), (_MANIFEST_WITH_TAB_SCANNER_ERROR, _CONFIG, None, ["item_1", "item_2", "default_item"]), ], - ids=["no_duplicates", "duplicates", "stream_configs_list", "scanner_error", "tab_scanner_error"], + ids=[ + "no_duplicates", + "duplicates", + "stream_configs_list", + "scanner_error", + "tab_scanner_error", + ], ) def test_dynamic_streams_read_with_config_components_resolver( manifest, config, expected_exception, expected_stream_names From 6c4ca2c4807229d475328ab8001e431a3d2e5156 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 26 Nov 2025 13:12:50 +0000 Subject: [PATCH 3/3] fix(low-code): handle tab character ScannerError specifically Per reviewer feedback, update the fix to specifically handle the tab character error case rather than catching all ScannerError exceptions. This maintains the existing pattern of handling specific error cases. Co-Authored-By: unknown <> --- .../declarative/resolvers/config_components_resolver.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/airbyte_cdk/sources/declarative/resolvers/config_components_resolver.py b/airbyte_cdk/sources/declarative/resolvers/config_components_resolver.py index de0fbf465..f4ce80aba 100644 --- a/airbyte_cdk/sources/declarative/resolvers/config_components_resolver.py +++ b/airbyte_cdk/sources/declarative/resolvers/config_components_resolver.py @@ -204,6 +204,10 @@ def _parse_yaml_if_possible(value: Any) -> Any: return yaml.safe_load(value) except ParserError: # "{{ record[0] in ['cohortActiveUsers'] }}" # not valid YAML return value - except ScannerError: # "%Y-%m-%d" or strings with tabs - not valid YAML - return value + except ScannerError as e: # "%Y-%m-%d" or strings with tabs - not valid YAML + if "expected alphabetic or numeric character, but found '%'" in str(e): + return value + if "found character '\\t' that cannot start any token" in str(e): + return value + raise e return value