deepset-ai / deepset-ai/haystack
OutputAdapter silently coerces string output to another type when output_type is a Union including str.
@anakin87 is already working on this.
Since Sep 5, 2026.
- Dominant language
- Python
- Stars
- 26.6k
- Forks
- 3.2k
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 194
Description
Describe the bug
OutputAdapter.run() skips ast.literal_eval coercion when output_type is exactly str, but not when output_type is a Union that includes str (e.g. str | None, Optional[str]). A rendered value like "42" declared with output_type=str | None is silently coerced to the int 42 instead of being preserved as the string "42".
Affected code
haystack/components/converters/output_adapter.py, inside run():
with contextlib.suppress(Exception):
if not self._unsafe and self.output_type is not str:
output_result = ast.literal_eval(output_result)
To Reproduce
from haystack.components.converters import OutputAdapter
adapter = OutputAdapter(template="{{ reply }}", output_type=str | None)
result = adapter.run(reply="42")
# Expected: {"output": "42"}
# Actual: {"output": 42} (coerced to int)
Context
This is the same class of bug just found and fixed in ConditionalRouter (see #12617, PR #12620), which has the identical output_type is not str pattern. I confirmed via GitHub search that no existing open issue or PR currently covers this specific OutputAdapter case before filing.
Proposed fix
Add a helper checking whether str is output_type itself or a member of a Union output_type, matching the same fix pattern used for ConditionalRouter. I have a fix and passing regression test ready.
Environment
Haystack main branch, Python 3.12.4
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.