deepset-ai/haystack · error · DeserializationError

{e}

Error message

{e}

What it means

When a type string contains a dot, deserialize_type() tries to import it with _import_class_by_name(); an ImportError there is re-raised as DeserializationError(str(e)) with this message. It means the module or class path stored in the serialized data could not be imported. This guards against loading pipelines that reference unavailable or blocked code.

Source

Thrown at haystack/utils/type_serialization.py:269

        # arguments.
        if main_type is typing.Literal:
            return typing.Literal[ast.literal_eval(f"({generics_str},)")]

        generic_args = [_deserialize_type_arg(arg) for arg in _parse_generic_args(generics_str)]

        # Reconstruct
        try:
            return main_type[tuple(generic_args) if len(generic_args) > 1 else generic_args[0]]
        except (TypeError, AttributeError) as e:
            raise DeserializationError(f"Could not apply arguments {generic_args} to type {main_type}") from e

    # Handle non-generic types
    # First, check if there's a module prefix
    if "." in type_str:
        try:
            return _import_class_by_name(type_str)
        except ImportError as e:
            raise DeserializationError(str(e)) from e

    # No module prefix, check builtins and typing.
    # (None / NoneType / Ellipsis are handled at the top of this function, before they can reach the
    # builtin type gate below which would refuse them for not being types.)
    if hasattr(builtins, type_str):
        resolved = getattr(builtins, type_str)
        # This bare-name path never consults the allowlist. A type annotation must resolve to an
        # actual type, so builtin functions like `eval`/`exec` are rejected while types pass.
        _check_builtin_is_type(resolved, type_str)
        return resolved

    # Then check typing
    if hasattr(typing, type_str):
        return getattr(typing, type_str)

    raise DeserializationError(f"Could not deserialize type: {type_str}")

View on GitHub (pinned to e318778c9b)

Solutions

  1. Install or fix the import path for the module referenced in the type string (pip install the package)
  2. Check for renames: update the serialized type string to the current module/class path
  3. If the class is intentionally blocked (haystack internal), use the public replacement type
  4. Reproduce with `from my.module import MyClass` to see the real import error

Example fix

// before
{"type": "haystack.testing.factory.TestComponent"}
// after
{"type": "my_app.components.TestComponent"}  # valid importable path
Defensive patterns

Strategy: try-catch

Validate before calling

import importlib
def can_import(dotted):
    mod, _, attr = dotted.rpartition(".")
    try:
        return hasattr(importlib.import_module(mod), attr)
    except ImportError:
        return False

Try / catch

from haystack.utils import DeserializationError
try:
    t = deserialize_type(type_str)
except DeserializationError as e:
    # str(e) is the underlying ImportError message
    raise RuntimeError(f"Cannot load pipeline, missing component: {e}") from e

Prevention

When it happens

Trigger: deserialize_type('my.module.MyClass') where my.module is not installed, renamed, or the class attribute no longer exists; loading a pipeline YAML created in another project/environment.

Common situations: Missing optional dependency in the target environment; package refactor renamed module paths between versions; pickled/serialized component schema shared across codebases.

Related errors


AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30). Data as JSON: /api/errors/40505bb6b0d7e049. Report an issue: GitHub.