{"record":{"id":"74f37798406b5683","repo":"deepset-ai/haystack","slug":"class-data-type-can-t-be-deserialized-as","errorCode":null,"errorMessage":"Class '{data['type']}' can't be deserialized as '{cls.__name__}'","messagePattern":"Class '(.+?)' can't be deserialized as '(.+?)'","errorType":"exception","errorClass":"DeserializationError","httpStatus":null,"severity":"error","filePath":"haystack/core/serialization.py","lineNumber":301,"sourceCode":"\n    :param cls:\n        The class to be used for deserialization.\n    :param data:\n        The serialized data.\n    :returns:\n        The deserialized object.\n\n    :raises DeserializationError:\n        If the `type` field in `data` is missing or it doesn't match the type of `cls`.\n    \"\"\"\n    # Copy so that replacing serialized sub-objects (Secret/ComponentDevice/nested components) with their\n    # deserialized instances below does not mutate the caller's ``data`` dict in place. Without this, a second\n    # deserialization of the same dict would receive already-parsed objects instead of their serialized form.\n    init_params = dict(data.get(\"init_parameters\", {}))\n    if \"type\" not in data:\n        raise DeserializationError(\"Missing 'type' in serialization data\")\n    if data[\"type\"] != generate_qualified_class_name(cls):\n        raise DeserializationError(f\"Class '{data['type']}' can't be deserialized as '{cls.__name__}'\")\n\n    valid_init_param_names = _init_parameter_names(cls)\n\n    # Automatically detect and deserialize objects with from_dict methods\n    for key, value in init_params.items():\n        if isinstance(value, dict) and \"type\" in value:\n            type_value = value.get(\"type\")\n            # Special handling for Secret (type == \"env_var\")\n            if type_value == \"env_var\":\n                init_params[key] = Secret.from_dict(value)\n            # Special handling for ComponentDevice (type == \"single\" or \"multiple\")\n            elif _is_serialized_component_device(value):\n                init_params[key] = ComponentDevice.from_dict(value)\n            # If type looks like a fully qualified class name, try to import it and deserialize\n            elif isinstance(type_value, str) and \".\" in type_value:\n                # Reject before importing if the parent class does not accept this parameter.\n                # This blocks YAML that smuggles untrusted classes into unused parameter slots.\n                if valid_init_param_names is not None and key not in valid_init_param_names:","sourceCodeStart":283,"sourceCodeEnd":319,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/core/serialization.py#L283-L319","documentation":"The serialized 'type' field must exactly match the fully-qualified name of the class being deserialized. default_from_dict() raises this when the data's 'type' points to a different class than the one from_dict() was called on, preventing construction of the wrong object from mislabeled data.","triggerScenarios":"Calling SomeComponent.from_dict(data) where data['type'] is a different class (e.g. renamed or moved class, copy-pasted serialized block, or loading a component dict into the wrong class).","commonSituations":"Class renamed/moved between haystack versions so old serialized pipelines carry the old qualified name; hand-copied YAML with a stale type string; custom component refactors changing module paths.","solutions":["Update data['type'] to the current fully-qualified class name.","Re-export the pipeline from an environment with the original component installed.","Check the haystack version and migrate serialized configs to the new class paths.","Ensure from_dict is called on the correct class rather than a sibling class."],"exampleFix":"// before\n{\"type\": \"haystack.nodes.retriever.sparse.ElasticsearchRetriever\", ...}\n\n// after\n{\"type\": \"haystack.components.retrievers.in_memory.InMemoryBM25Retriever\", ...}","handlingStrategy":"validation","validationCode":"from haystack.core.serialization import generate_qualified_class_name\nassert data.get(\"type\") == generate_qualified_class_name(MyComponent), data.get(\"type\")","typeGuard":"def matches_class(data: dict, cls) -> bool:\n    from haystack.core.serialization import generate_qualified_class_name\n    return isinstance(data, dict) and data.get(\"type\") == generate_qualified_class_name(cls)","tryCatchPattern":"from haystack.core.errors import DeserializationError\ntry:\n    comp = MyComponent.from_dict(data)\nexcept DeserializationError as e:\n    if \"can't be deserialized as\" in str(e):\n        data[\"type\"] = generate_qualified_class_name(MyComponent)\n        comp = MyComponent.from_dict(data)","preventionTips":["Update serialized 'type' strings after class renames/moves","Pin haystack versions between pipeline export and load","Re-export pipelines rather than hand-editing type fields"],"tags":["deserialization","haystack","version-migration"],"backgroundTag":"class-type-mismatch-deserialization","analyzedSha":"e318778c9bf60a1963e3b5f451359655dd696c30","analyzedAt":"2026-08-30T11:45:20.711Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}