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

  1. Verify server_url points to an actual Mermaid renderer and test with curl -i
  2. Check whether a proxy/firewall is intercepting the response (inspect response headers/logs)
  3. If self-hosting, confirm the renderer serves the requested content type
  4. 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

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


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