deepset-ai/haystack · error · PipelineDrawingError
The Mermaid server response does not look like a valid {expe
Error message
The Mermaid server response does not look like a valid {expected_label}. This can happen if 'server_url' points to a server that is not a Mermaid renderer. To avoid writing untrusted content to disk, no file will be saved. What it means
Haystack checks the magic bytes of the Mermaid server's response body against the requested format (PNG/SVG/PDF signatures) so untrusted content is never written to disk. If the body does not match the expected format — typically because server_url points to something that is not a Mermaid renderer — this PipelineDrawingError is raised.
Source
Thrown at haystack/core/pipeline/draw.py:240
content_type_prefixes = ("image/webp",)
body_ok = content[0:4] == _RIFF_SIGNATURE and content[8:12] == _WEBP_SIGNATURE
else: # png (default)
expected_label = "PNG image"
content_type_prefixes = ("image/png",)
body_ok = content.startswith(_PNG_SIGNATURE)
# The Content-Type header is server-controlled, so a mismatch is only a warning: the
# authoritative check is the body signature below.
content_type = resp.headers.get("content-type", "").split(";")[0].strip().lower()
if content_type and not content_type.startswith(content_type_prefixes):
logger.warning(
"The Mermaid server returned an unexpected Content-Type '{content_type}' (expected {expected}).",
content_type=content_type,
expected=expected_label,
)
if not body_ok:
raise PipelineDrawingError(
f"The Mermaid server response does not look like a valid {expected_label}. "
f"This can happen if 'server_url' points to a server that is not a Mermaid renderer. "
f"To avoid writing untrusted content to disk, no file will be saved."
)
def _to_mermaid_image(
graph: networkx.MultiDiGraph,
server_url: str = "https://mermaid.ink",
params: dict | None = None,
timeout: int = 30,
super_component_mapping: dict[str, str] | None = None,
) -> bytes:
"""
Renders a pipeline using a Mermaid server.
:param graph:
The graph to render as a Mermaid pipeline.View on GitHub (pinned to e318778c9b)
Solutions
- Verify server_url points to an actual Mermaid renderer and test with curl -i
- Check whether a proxy/firewall is intercepting the response (inspect response headers/logs)
- If self-hosting, confirm the renderer serves the requested content type
- Retry with the default https://mermaid.ink to isolate the issue
Example fix
// before pipeline.draw(path="graph.pdf", server_url="http://localhost:8080") # serves HTML // after pipeline.draw(path="graph.pdf", server_url="https://mermaid.ink")
Defensive patterns
Strategy: try-catch
Validate before calling
r = requests.get(server_url, timeout=10)
ct = r.headers.get("content-type", "")
if "html" in ct.lower():
raise RuntimeError(f"{server_url} is not a Mermaid renderer (returned HTML)") Type guard
def looks_like_mermaid_server(url: str) -> bool:
try:
r = requests.get(url, timeout=5)
return "html" not in r.headers.get("content-type", "").lower()
except requests.RequestException:
return False Try / catch
try:
pipeline.draw(path="graph.png", server_url=URL)
except PipelineDrawingError as e:
if "does not look like a valid" in str(e):
logger.error("server_url misconfigured: %s", URL)
else:
... Prevention
- Never point server_url at proxies/portals; test with curl -i first
- Check for corporate proxy interference
- Pin a known-good renderer for automated diagram generation
When it happens
Trigger: server_url points to an HTML page, auth portal, or non-renderer service that returns HTML/JSON/text instead of image bytes; or the server returns an image in a different format than requested (e.g., PNG returned when PDF asked).
Common situations: Corporate proxies returning login pages, wrong port hitting a different service, typo'd server_url, self-hosted renderer misconfigured to always serve a default page, or API gateways that intercept and rewrite responses.
Related errors
- The Mermaid server returned an empty response; no image will
- There was an issue with {server_url}, see the stacktrace for
- tool_concurrency_limit must be greater than or equal to 1.
- Document with ID '{doc.id}' has a file path '{file_path}' th
- Refusing to deserialize an OutputAdapter with unsafe=True wh
AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30).
Data as JSON: /api/errors/7fe4e3b54e35fe4b.
Report an issue: GitHub.