# How to Debug Graphviz-to-Draw.io Conversion Issues with graphviz2drawio

> Debug graphviz2drawio conversion issues by enabling DEBUG logging, catching specific errors like MissingTitleError, and inspecting SVG output to pinpoint failures in pygraphviz, SVG parsing, or XML generation.

- Repository: [Harold Martin/graphviz2drawio](https://github.com/hbmartin/graphviz2drawio)
- Tags: how-to-guide
- Published: 2026-03-03

---

**Enable `logging.DEBUG`, catch specific exceptions like `MissingTitleError` or `UnableToParseGraphError`, and inspect the intermediate SVG output to isolate whether failures originate from pygraphviz, the SVG parser, or the XML generation stage.**

The `graphviz2drawio` library transforms Graphviz DOT files into Draw.io-compatible XML through a multi-stage pipeline involving pygraphviz, SVG rendering, and custom attribute enrichment. When debugging conversion failures, you must identify which of the three conversion stages—loading the Graphviz model, parsing the SVG, or generating the final XML—is producing the error. This guide provides targeted debugging strategies based on the actual source code implementation in the `hbmartin/graphviz2drawio` repository.

## Understanding the Conversion Pipeline

The conversion process in [`graphviz2drawio/graphviz2drawio.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/graphviz2drawio.py) executes three distinct operations that serve as failure isolation points:

1. **Load the Graphviz model** – The `_load_pygraphviz_agraph` function builds a `pygraphviz.AGraph` object from a file path, DOT string, or file-like object. This stage includes detection of DOT strings, handling of comments, and a bug workaround for pygraphviz issue #55.

2. **Render to SVG and parse** – The `graph.draw(prog=layout_prog, format="svg")` method produces an SVG byte-string that `parse_nodes_edges_clusters` in [`graphviz2drawio/models/SvgParser.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/models/SvgParser.py) (lines 23–81) transforms into internal **nodes**, **edges**, and **clusters** objects. This extraction handles gradients, titles, and parallel edge merging.

3. **Enrich attributes and build XML** – The code enriches parsed edges and nodes with original Graphviz attribute dictionaries (lines 39–45 for edges, lines 48–50 for nodes in [`graphviz2drawio.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio.py)), then the `MxGraph` class writes the final Draw.io XML structure.

Because the pipeline spans multiple subsystems, errors typically manifest in specific stages with distinct symptoms.

## Common Failure Types and Solutions

### Unable to Render SVG

**Typical symptom:** `UnableToParseGraphError` raised from [`graphviz2drawio/models/Errors.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/models/Errors.py) (lines 56–62) with the message that `graph.draw()` returned `None`.

**Debug actions:**
- Verify pygraphviz installation: `python -c "import pygraphviz"`
- Test the layout program manually: `dot -Tsvg mygraph.gv > out.svg`
- Confirm the layout program (`dot`, `neato`, etc.) is available in your system `$PATH`

### Missing Title in SVG Elements

**Typical symptom:** `MissingTitleError` raised from [`graphviz2drawio/models/Errors.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/models/Errors.py) (lines 22–28), indicating a node or edge lacks a title attribute.

**Debug actions:**
- Open the generated SVG and inspect `<g class="node">` or `<g class="edge">` elements for missing preceding comments (`<!-- node_id -->`)
- Ensure the original DOT file supplies labels using `[label="..."]` attributes or comment lines (`// ...`)

### Incorrect Edge Label Merging

**Typical symptom:** Duplicate edge labels appear or labels are lost entirely.

**Debug actions:**
- Print the `edge.key_for_label` for each parsed edge in [`graphviz2drawio/models/SvgParser.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/models/SvgParser.py) (lines 64–73)
- Compare with the `graph_edges` dictionary created in [`graphviz2drawio/graphviz2drawio.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/graphviz2drawio.py) (lines 19–24)
- If keys differ, the SVG uses multi-line labels—adjust parsing or supply explicit `xlabel`/`label` attributes in the DOT file

### Wrong Geometry or Positions

**Typical symptom:** Nodes appear in incorrect locations or edges appear stretched.

**Debug actions:**
- Dump `Rect` objects using `print(node.rect)` to verify parsed coordinates
- Verify the coordinate translation in `CoordsTranslate.from_svg_transform` matches the SVG `transform` attribute
- Ensure the graph’s `layout_prog` produces non-scaled SVG using `-Gsize` or `-Gdpi` options

### Missing or Malformed Gradients

**Typical symptom:** Colors fallback to black or transparent instead of the defined gradient.

**Debug actions:**
- Inspect `<linearGradient>` or `<radialGradient>` sections in the SVG
- Look for missing `stop-color` or `stop-opacity` styles in `SvgParser._extract_gradients` (lines 96–135)
- Provide explicit `style="stop-color:#RRGGBB;stop-opacity:1"` in the DOT file or upgrade Graphviz to a version generating more robust gradients

### Unexpected Exceptions

**Typical symptom:** Traceback not covered by the custom error hierarchy.

**Debug actions:**
- Wrap conversion in `try/except` to print the full traceback
- Enable `logging.basicConfig(level=logging.DEBUG)` to see internal state including node counts, edge counts, and SVG size

## Step-by-Step Debugging Workflow

Use this complete script to isolate failures across the conversion pipeline:

```python
import logging
from pathlib import Path
from graphviz2drawio import convert
from graphviz2drawio.models.Errors import (
    UnableToParseGraphError,
    MissingTitleError,
)

logging.basicConfig(level=logging.DEBUG)   # View internal debug output

graph_path = Path("examples/broken.gv")

try:
    drawio_xml = convert(graph_path, layout_prog="dot")
    Path("out.drawio").write_text(drawio_xml, encoding="utf-8")
    print("✅ conversion succeeded")
except MissingTitleError as e:
    print("❌ missing title:", e)
except UnableToParseGraphError as e:
    print("❌ graphviz could not produce SVG:", e)
except Exception as e:                     # Catch-all for unexpected bugs

    import traceback
    traceback.print_exc()

```

**Key isolation techniques illustrated:**
- Import specific exception classes (`MissingTitleError`, `UnableToParseGraphError`) to distinguish between parsing and generation failures
- Enable `logging.DEBUG` to watch internal dictionary construction in [`graphviz2drawio.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio.py) (e.g., `graph_edges`, `graph_nodes`)
- Write resulting XML to disk for visual verification in Draw.io

## Quick Diagnostic Checks

- **Verify pygraphviz functionality**: Run `python -c "import pygraphviz; print(pygraphviz.__version__)"`. Look for: No ImportError confirms installation.
- **Test the layout program**: Run `dot -Tsvg -O mygraph.gv`. Look for: Successful generation of `mygraph.gv.svg`.
- **Inspect SVG structure**: Open `mygraph.gv.svg` in any viewer. Look for: `<g class="node">` elements should have preceding comments (`<!-- node_id -->`).
- **Count parsed entities**: Add `print(len(nodes), len(edges), len(clusters))` after `parse_nodes_edges_clusters`. Look for: Counts should match the number of elements in the original DOT file.

## Practical Debug Code Examples

### Minimal Conversion with Error Handling

This example demonstrates the standard entry point with proper exception handling:

```python
from pathlib import Path
from graphviz2drawio import convert
from graphviz2drawio.models.Errors import UnableToParseGraphError, MissingTitleError

dot_file = Path("mygraph.gv")          # Can also be a string with DOT source

try:
    drawio_xml = convert(dot_file)     # Default layout program is "dot"

    Path("mygraph.drawio").write_text(drawio_xml)
    print("✅ Draw.io file written")
except MissingTitleError as exc:
    print("❌ A node or edge is missing a title:", exc)
except UnableToParseGraphError as exc:
    print("❌ Graphviz could not generate SVG:", exc)

```

*References:* `convert` implementation ([`graphviz2drawio.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio.py) lines 13–50), custom errors ([`Errors.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/Errors.py) lines 22–28).

### Inspecting Intermediate SVG Output

When visual output is wrong, examine the SVG before XML conversion:

```python
from graphviz2drawio import _load_pygraphviz_agraph

g = _load_pygraphviz_agraph("mygraph.gv")
svg_bytes = g.draw(prog="dot", format="svg")
Path("debug.svg").write_bytes(svg_bytes)      # Open in browser to inspect

print("🔍 SVG written – inspect titles/comments for nodes/edges")

```

*Reference:* SVG generation logic ([`graphviz2drawio.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio.py) lines 29–33).

### Logging Internal Parsing Statistics

Verify that the SVG parser correctly identifies all entities:

```python
import logging
from graphviz2drawio.models.SvgParser import parse_nodes_edges_clusters

logging.basicConfig(level=logging.DEBUG)

# Assuming svg_bytes obtained from previous step

nodes, edges, clusters = parse_nodes_edges_clusters(svg_bytes, is_directed=True)

logging.debug("Parsed %d nodes, %d edges, %d clusters",
              len(nodes), len(edges), len(clusters))

```

*Reference:* Parser entry point ([`SvgParser.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/SvgParser.py) lines 23–28).

## Key Source Files for Debugging

- **[`graphviz2drawio/graphviz2drawio.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/graphviz2drawio.py)**: Public `convert` API and orchestration. Critical functions include `_load_pygraphviz_agraph` and attribute enrichment (lines 39–50).
- **[`graphviz2drawio/models/Errors.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/models/Errors.py)**: Custom exception hierarchy. Contains `MissingTitleError` (lines 22–28) and `UnableToParseGraphError` (lines 56–62).
- **[`graphviz2drawio/models/SvgParser.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/models/SvgParser.py)**: SVG parsing and entity extraction. Key logic in `parse_nodes_edges_clusters` (lines 23–81) and `_extract_gradients` (lines 96–135).
- **[`graphviz2drawio/mx/MxGraph.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/mx/MxGraph.py)**: Draw.io XML generation. Coordinate handling in `add_mx_geo_with_points` (lines 30–48).
- **[`graphviz2drawio/mx/Edge.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/mx/Edge.py)**: Edge styling and geometry calculations in `get_edge_style` (lines 64–73).

## Summary

- **Isolate the failure stage** using the three-phase pipeline: AGraph loading (pygraphviz), SVG parsing ([`SvgParser.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/SvgParser.py)), or XML generation ([`MxGraph.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/MxGraph.py)).
- **Catch specific exceptions** (`MissingTitleError`, `UnableToParseGraphError`) rather than generic `Exception` to identify whether the DOT file, SVG output, or coordinate translation is at fault.
- **Enable debug logging** to view internal counts of nodes, edges, and clusters during the conversion process.
- **Inspect intermediate SVG** manually when geometry or styling appears incorrect in the final Draw.io output.
- **Verify system dependencies** by running `dot -Tsvg` independently to ensure Graphviz layout programs are correctly installed and accessible in `$PATH`.

## Frequently Asked Questions

### Why does the conversion fail with "Unable to parse graph" even though my DOT file works in other tools?

This error originates from `UnableToParseGraphError` in [`graphviz2drawio/models/Errors.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/models/Errors.py) when `graph.draw()` returns `None`. The issue typically indicates that pygraphviz cannot find the Graphviz layout program (e.g., `dot`) in your system path, or the DOT syntax contains constructs that pygraphviz cannot process. Run `dot -Tsvg yourfile.gv` manually to verify the layout engine works independently of Python.

### How do I fix missing titles for nodes or edges in the generated Draw.io diagram?

The `MissingTitleError` in [`graphviz2drawio/models/Errors.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/models/Errors.py) (lines 22–28) triggers when the SVG parser cannot find a comment or label attribute identifying an element. Ensure your DOT file includes explicit labels like `[label="NodeName"]` for nodes, or that the Graphviz comment format (`// node_id`) is preserved in the SVG output. Open the intermediate SVG file to verify that `<g class="node">` elements have preceding HTML comments containing the element ID.

### Why are edge labels duplicated or missing after conversion?

This occurs when `edge.key_for_label` values in [`graphviz2drawio/models/SvgParser.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/models/SvgParser.py) (lines 64–73) do not match the keys in the `graph_edges` dictionary built in [`graphviz2drawio/graphviz2drawio.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/graphviz2drawio.py) (lines 19–24). Multi-line labels or special characters in the DOT file can cause key mismatches. Supply explicit `xlabel` attributes in your DOT file or print the edge keys during debugging to identify the specific label causing the merge conflict.

### How can I verify that coordinate positions are being calculated correctly?

Dump the `Rect` objects from parsed nodes using `print(node.rect)` and compare them with the SVG's `transform` attribute processed by `CoordsTranslate.from_svg_transform`. If positions appear wrong in Draw.io, check that your Graphviz command does not apply scaling factors—avoid `-Gsize` attributes that resize the output, or ensure DPI settings match between the layout program and the SVG parser expectations in [`graphviz2drawio/mx/MxGraph.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/mx/MxGraph.py) (lines 30–48).