Repository: deepset-ai/haystack

Issue:
bug: Successfully imported module XXX but can't find it in the component registry.This is unexpected and most likely a bug.
**Describe the bug**
I have the following situation:
- a service using pipeline deserialization from yaml and executing the pipelines
- a custom components package

The custom components package is in the format:

```
comp/
    __init__.py
    A/
       __init__.py
       B/
            __init__.py
            b.py
```

in which the `comp/A/B/b.py` file is (in pseudo code): 

```python
from haystack import component

@component
class BComponent:

   def __init__(self, some_param: str):
      self.some_param = some_param

  @component.output_types(some_return=Any)
  def run(some_input: Any):
       # do some stuff...
       return {"some_input": ...}
```

The `comp/A/B/__init__.py` file is 

```python
from .b import BComponent

__all__ = ["BComponent"]
```


If the pipeline is written in yaml as: 

```yaml
components:
   b:
     init_parameters:... 
    type: comp.A.B.BComponent
```

I have the following error:

```
  File "[omitted]/.venv/lib/python3.12/site-packages/haystack/core/pipeline/base.py", line 167, in from_dict
    raise PipelineError(
haystack.core.errors.PipelineError: Successfully imported module comp.A.B but can't find it in the component registry.This is unexpected and most likely a bug.
```

If I write the fully qualified name:

```yaml
components:
   b:
     init_parameters:... 
    type: comp.A.B.b.BComponent
```

it works perfectly.




**Error message**
```
  File "[omitted]/.venv/lib/python3.12/site-packages/haystack/core/pipeline/base.py", line 167, in from_dict
    raise PipelineError(
haystack.core.errors.PipelineError: Successfully imported module comp.A.B but can't find it in the component registry.This is unexpected and most likely a bug.
```

**Expected behavior**
The `from_dict` method of the Base Pipeline to support external exported symbols 


**To Reproduce**

1. Write a package structure as in the previous example
2. create a new project
3. import the package
4. write the yaml with the exported name
5. write the following code:

```python
from haystack import Pipeline


ptext = """
components:
   b:
     init_parameters:... 
    type: comp.A.B.BComponent
"""

p = Pipeline.loads(ptext)
```

6. execute the code 


**FAQ Check**
- [ x] Have you had a look at [our new FAQ page](https://docs.haystack.deepset.ai/docs/faq)?

**System:**
 - OS: MacOS M4 Pro (doesn't matter... even in x86 docker images is the same)
 - Haystack version (commit or version number): 2.8.0



Discussion:

Patch:
diff --git a/haystack/core/pipeline/base.py b/haystack/core/pipeline/base.py
index 9f976fd216..666c04ce26 100644
--- a/haystack/core/pipeline/base.py
+++ b/haystack/core/pipeline/base.py
@@ -197,12 +197,15 @@ def from_dict(
                         # ...then try again
                         if component_data["type"] not in component.registry:
                             raise PipelineError(
-                                f"Successfully imported module {module} but can't find it in the component registry."
-                                "This is unexpected and most likely a bug."
+                                f"Successfully imported module '{module}' but couldn't find "
+                                f"'{component_data['type']}' in the component registry.\n"
+                                f"The component might be registered under a different path. "
+                                f"Here are the registered components:\n {list(component.registry.keys())}\n"
                             )
                     except (ImportError, PipelineError, ValueError) as e:
                         raise PipelineError(
-                            f"Component '{component_data['type']}' (name: '{name}') not imported."
+                            f"Component '{component_data['type']}' (name: '{name}') not imported. Please "
+                            f"check that the package is installed and the component path is correct."
                         ) from e
 
                 # Create a new one


Test patch:
diff --git a/test/core/pipeline/test_pipeline_base.py b/test/core/pipeline/test_pipeline_base.py
index 802f86ec6c..55529e282f 100644
--- a/test/core/pipeline/test_pipeline_base.py
+++ b/test/core/pipeline/test_pipeline_base.py
@@ -606,7 +606,30 @@ def test_from_dict_with_invalid_type(self):
         with pytest.raises(PipelineError) as err:
             PipelineBase.from_dict(data)
 
-        err.match(r"Component '' \(name: 'add_two'\) not imported.")
+        err.match(
+            r"Component '' \(name: 'add_two'\) not imported. Please check that the package is installed and the component path is correct."
+        )
+
+    def test_from_dict_with_correct_import_but_invalid_type(self):
+        # Test case: Module imports but component not found in registry.
+        data_registry_error = {
+            "metadata": {"test": "test"},
+            "components": {"add_two": {"type": "haystack.testing.NonExistentComponent", "init_parameters": {"add": 2}}},
+            "connections": [],
+        }
+
+        # Patch thread_safe_import so it doesn't raise an ImportError.
+        with patch("haystack.utils.type_serialization.thread_safe_import") as mock_import:
+            mock_import.return_value = None
+            with pytest.raises(PipelineError) as err_info:
+                PipelineBase.from_dict(data_registry_error)
+            outer_message = str(err_info.value)
+            inner_message = str(err_info.value.__cause__)
+
+            assert "Component 'haystack.testing.NonExistentComponent' (name: 'add_two') not imported." in outer_message
+            assert "Successfully imported module 'haystack.testing' but couldn't find" in inner_message
+            assert "in the component registry." in inner_message
+            assert "registered under a different path." in inner_message
 
     # UNIT
     def test_from_dict_without_connection_sender(self):