diff --git a/src/lfx/src/lfx/interface/listing.py b/src/lfx/src/lfx/interface/listing.py index e051e34c4e..c96bcc519a 100644 --- a/src/lfx/src/lfx/interface/listing.py +++ b/src/lfx/src/lfx/interface/listing.py @@ -17,10 +17,14 @@ class AllTypesDict(LazyLoadDictBase): @override def get_type_dict(self): - from lfx.custom.utils import get_all_types_dict + # Must stay synchronous: this is reached from the sync `all_types_dict` property during + # graph build (vertex base_type fallback). Use the sync builder, not the async + # `get_all_types_dict` (returning its un-awaited coroutine raised + # "'coroutine' object is not a mapping"). + from lfx.custom.utils import build_custom_components settings_service = get_settings_service() - return get_all_types_dict(settings_service.settings.components_path) + return build_custom_components(settings_service.settings.components_path) lazy_load_dict = AllTypesDict() diff --git a/src/lfx/tests/unit/interface/test_listing.py b/src/lfx/tests/unit/interface/test_listing.py new file mode 100644 index 0000000000..478ae887d1 --- /dev/null +++ b/src/lfx/tests/unit/interface/test_listing.py @@ -0,0 +1,20 @@ +"""Tests for lfx.interface.listing — the synchronous all-types lookup.""" + +from __future__ import annotations + + +def test_all_types_dict_is_a_mapping_not_a_coroutine(): + """`all_types_dict` must return a real mapping synchronously. + + Regression: `get_type_dict` called the async `get_all_types_dict` without awaiting it, + so the sync `_build_dict` did `{**coroutine}` and raised + "'coroutine' object is not a mapping". This path is reached during graph build (a vertex + falling back to look up its base_type), so every flow that hit it failed to load. + """ + from lfx.interface.listing import AllTypesDict + + result = AllTypesDict().all_types_dict + + assert isinstance(result, dict) + # The sync builder discovers the bundled component categories plus the "Custom" entry. + assert "Custom" in result