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
- If you trust the source, load with Pipeline.loads(yaml_str, unsafe=True) (or Pipeline.load(path, unsafe=True)).
- If you don't need NativeEnvironment, re-save the pipeline with ConditionalRouter(unsafe=False) and load normally.
- 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
- Prefer unsafe=False routers; only serialize unsafe=True when NativeEnvironment features are required.
- Never load untrusted pipeline YAML with unsafe=True.
- Grep pipeline YAML for 'unsafe: true' before loading.
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
- Refusing to deserialize a ConditionalRouter with custom filt
- Refusing to deserialize an OutputAdapter with unsafe=True wh
- Refusing to deserialize an OutputAdapter with custom filters
- Refusing to deserialize '{handle}': it resolves to '{name}',
- Refusing to deserialize '{handle}': it traverses into the in
AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30).
Data as JSON: /api/errors/8d83c9731d1e2fe4.
Report an issue: GitHub.