deepset-ai/haystack · error · DeserializationError

Refusing to deserialize a ConditionalRouter with unsafe=True

Error message

Refusing to deserialize a ConditionalRouter with unsafe=True while loading in safe mode. If you trust the source of this data, load it with Pipeline.load(..., unsafe=True).

What it means

ConditionalRouter was serialized with unsafe=True (which swaps the Jinja sandbox for a NativeEnvironment that executes arbitrary code), and it is now being deserialized while the pipeline is loading in safe mode. Haystack refuses to honor the unsafe flag from serialized data alone, because a hostile pipeline YAML could otherwise disable its own sandbox during Pipeline.loads in default safe mode. A DeserializationError is raised to force an explicit trust decision.

Source

Thrown at haystack/components/routers/conditional_router.py:373

        )

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "ConditionalRouter":
        """
        Deserializes the component from a dictionary.

        :param data:
            The dictionary to deserialize from.
        :returns:
            The deserialized component.
        """
        init_params = data.get("init_parameters", {})

        # `unsafe=True` swaps the Jinja sandbox for a NativeEnvironment that executes arbitrary code.
        # Honor it from serialized data only when the whole pipeline is being loaded in unsafe mode;
        # otherwise a hostile pipeline could disable the sandbox on its own in default safe mode.
        if init_params.get("unsafe") and not _is_unsafe_deserialization():
            raise DeserializationError(
                "Refusing to deserialize a ConditionalRouter with unsafe=True while loading in safe mode. "
                "If you trust the source of this data, load it with Pipeline.load(..., unsafe=True)."
            )

        custom_filters = init_params.get("custom_filters", {})
        if custom_filters and not _is_unsafe_deserialization():
            raise DeserializationError(
                "Refusing to deserialize a ConditionalRouter with custom filters while loading in safe mode. "
                "Custom filters are arbitrary callables that can execute during pipeline loading. "
                "If you trust the source of this data, load it with Pipeline.load(..., unsafe=True)."
            )

        routes = init_params.get("routes")
        for route in routes:
            # output_type needs to be deserialized from a string to a type
            if isinstance(route["output_type"], list):
                route["output_type"] = [deserialize_type(t) for t in route["output_type"]]
            else:

View on GitHub (pinned to e318778c9b)

Solutions

  1. If you trust the source, load with Pipeline.loads(yaml_str, unsafe=True) (or Pipeline.load(path, unsafe=True)).
  2. If you don't need NativeEnvironment, re-save the pipeline with ConditionalRouter(unsafe=False) and load normally.
  3. Inspect the YAML's init_parameters.unsafe field before loading to decide whether the source is trustworthy.

Example fix

// before
pipe = Pipeline.load("pipe.yaml")
// after
pipe = Pipeline.load("pipe.yaml", unsafe=True)  # only if source is trusted
Defensive patterns

Strategy: validation

Validate before calling

data = yaml.safe_load(open("pipe.yaml"))
for c in data["components"].values():
    p = c.get("init_parameters", {})
    if p.get("unsafe"):
        # decide trust, then: Pipeline.load("pipe.yaml", unsafe=True)
        raise RuntimeError("pipeline requires unsafe=True to load")

Type guard

def needs_unsafe(component_data: dict) -> bool:
    return bool(component_data.get("init_parameters", {}).get("unsafe", False))

Try / catch

try:
    pipe = Pipeline.load("pipe.yaml")
except DeserializationError:
    if trusted("pipe.yaml"):
        pipe = Pipeline.load("pipe.yaml", unsafe=True)
    else:
        raise

Prevention

When it happens

Trigger: Calling Pipeline.load()/ConditionalRouter.from_dict() on YAML/JSON whose init_parameters contains unsafe: true, without passing unsafe=True to Pipeline.load.

Common situations: Loading a pipeline saved by someone who ran ConditionalRouter(unsafe=True) locally for NativeEnvironment Jinja features; sharing pipelines across machines; upgrading from older Haystack versions where unsafe flags were silently honored on load.

Related errors


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