{"record":{"id":"b16afd5d7dd21c5f","repo":"deepset-ai/haystack","slug":"refusing-to-deserialize-an-outputadapter-with-unsa","errorCode":null,"errorMessage":"Refusing to deserialize an OutputAdapter with unsafe=True while loading in safe mode. If you trust the source of this data, load it with Pipeline.load(..., unsafe=True).","messagePattern":"Refusing to deserialize an OutputAdapter with unsafe=True while loading in safe mode\\. If you trust the source of this data, load it with Pipeline\\.load\\(\\.\\.\\., unsafe=True\\)\\.","errorType":"exception","errorClass":"DeserializationError","httpStatus":null,"severity":"critical","filePath":"haystack/components/converters/output_adapter.py","lineNumber":180,"sourceCode":"        )\n\n    @classmethod\n    def from_dict(cls, data: dict[str, Any]) -> \"OutputAdapter\":\n        \"\"\"\n        Deserializes the component from a dictionary.\n\n        :param data:\n            The dictionary to deserialize from.\n        :returns:\n            The deserialized component.\n        \"\"\"\n        init_params = data.get(\"init_parameters\", {})\n\n        # `unsafe=True` swaps the Jinja sandbox for a NativeEnvironment that executes arbitrary code.\n        # Honor it from serialized data only when the whole pipeline is being loaded in unsafe mode;\n        # otherwise a hostile pipeline could disable the sandbox on its own in default safe mode.\n        if init_params.get(\"unsafe\") and not _is_unsafe_deserialization():\n            raise DeserializationError(\n                \"Refusing to deserialize an OutputAdapter with unsafe=True while loading in safe mode. \"\n                \"If you trust the source of this data, load it with Pipeline.load(..., unsafe=True).\"\n            )\n\n        custom_filters = init_params.get(\"custom_filters\", {})\n        if custom_filters and not _is_unsafe_deserialization():\n            raise DeserializationError(\n                \"Refusing to deserialize an OutputAdapter with custom filters while loading in safe mode. \"\n                \"Custom filters are arbitrary callables that can execute during pipeline loading. \"\n                \"If you trust the source of this data, load it with Pipeline.load(..., unsafe=True).\"\n            )\n\n        init_params[\"output_type\"] = deserialize_type(init_params[\"output_type\"])\n\n        if custom_filters:\n            init_params[\"custom_filters\"] = {\n                name: deserialize_callable(filter_func) if filter_func else None\n                for name, filter_func in custom_filters.items()","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/components/converters/output_adapter.py#L162-L198","documentation":"OutputAdapter.from_dict refuses to restore a serialized component whose init_parameters contain unsafe=True when the pipeline is being loaded in safe mode. unsafe=True swaps the Jinja sandbox for a NativeEnvironment that can execute arbitrary code, so honoring it from data alone would let a hostile pipeline YAML/JSON escape the sandbox.","triggerScenarios":"Pipeline.load(path) (default safe mode) on a pipeline file saved with OutputAdapter(unsafe=True); loading untrusted third-party pipeline definitions containing unsafe:true in the OutputAdapter's init_parameters.","commonSituations":"Downloading shared pipeline recipes from the internet; upgrading Haystack where serialized pipelines exported with unsafe=True now get rejected at load; CI loading stored pipeline artifacts.","solutions":["If you trust the file's source, load with Pipeline.loads(data, unsafe=True)","Re-save the pipeline with OutputAdapter(unsafe=False) and verify the template still works in the sandbox","Remove unsafe=True from the serialized init_parameters if the template doesn't need it"],"exampleFix":"// before\npipeline = Pipeline.loads(data)\n// after\npipeline = Pipeline.loads(data, unsafe=True)  # only if you trust this pipeline's source","handlingStrategy":"try-catch","validationCode":"import yaml\ndef uses_unsafe_adapter(path):\n    data = yaml.safe_load(open(path))\n    return any(\n        c.get(\"type\") == \"OutputAdapter\" and c.get(\"init_parameters\", {}).get(\"unsafe\")\n        for c in data.get(\"components\", []).values()\n    )","typeGuard":null,"tryCatchPattern":"try:\n    pipeline = Pipeline.load(path)\nexcept DeserializationError as e:\n    if \"unsafe=True\" in str(e) and is_trusted_source(path):\n        pipeline = Pipeline.load(path, unsafe=True)\n    else:\n        raise","preventionTips":["Never load pipeline files from untrusted sources with unsafe=True","Audit serialized pipelines for unsafe:true before loading","Prefer sandboxed templates (unsafe=False) so safe-mode loading works"],"tags":["python","haystack","deserialization","security","sandbox-escape"],"backgroundTag":"unsafe-deserialization-blocked","analyzedSha":"e318778c9bf60a1963e3b5f451359655dd696c30","analyzedAt":"2026-08-30T11:45:20.711Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}