Error Handling Mechanisms in graphviz2drawio: Custom Exceptions and CLI Recovery

graphviz2drawio implements a layered error-handling strategy combining a custom exception hierarchy, defensive validation checks, and user-friendly CLI error reporting to ensure robust GraphViz-to-DrawIO conversion.

The hbmartin/graphviz2drawio library converts GraphViz DOT files into DrawIO-compatible MXGraph format. Understanding the error handling mechanisms in graphviz2drawio is essential for both library consumers integrating the Python API and command-line users processing batch conversions. The codebase employs specific custom exceptions defined in graphviz2drawio/models/Errors.py alongside strategic try/except blocks to manage malformed SVG data, invalid GraphViz output, and encoding issues.

Custom Exception Hierarchy

All conversion-specific errors inherit from the base class GdValueError, defined in graphviz2drawio/models/Errors.py. This design allows callers to catch any graphviz2drawio-specific failure using a single except GdValueError: clause while still permitting granular exception handling.

The library defines six specific exception types for distinct failure modes:

  • CouldNotParsePathError – Raised when an SVG element contains unparsable path data in its d attribute (lines 13–19)
  • MissingTitleError – Triggered when a <g> element representing a node, edge, or cluster lacks a required title comment (lines 22–28)
  • MissingTextError – Indicates a text element is missing required attributes (lines 31–37)
  • InvalidBezierParameterError – Occurs when Bézier subdivision receives a parameter t outside the valid range [0, 1] (lines 40–45)
  • MissingIdentifiersError – Raised when a node or edge SVG element lacks both an id attribute and a title (lines 47–53)
  • UnableToParseGraphError – Signals that pygraphviz.AGraph.draw() returned None, indicating invalid GraphViz output (lines 56–62)

Defensive Checks and Explicit Raises

Throughout the core conversion pipeline, functions employ defensive programming with explicit raise statements to fail fast and provide specific context about validation failures.

Node and Edge Validation

In graphviz2drawio/mx/NodeFactory.from_svg, the factory validates that both sid (SVG id) and gid (title) are present before creating a node object. If either identifier is missing, it immediately raises MissingIdentifiersError(sid, gid) to guarantee every node has a unique reference.

Similarly, graphviz2drawio/models/SvgParser.parse_nodes_edges_clusters iterates through SVG group elements and ensures each contains a title comment. When a group lacks this required metadata, it raises MissingTitleError(g) to prevent silent data loss during conversion.

Geometric and Graph Validation

The Bézier curve processing in graphviz2drawio/mx/bezier.subdivide validates that the subdivision parameter t falls within the inclusive range [0, 1]. An illegal value triggers InvalidBezierParameterError(t), stopping curve corruption before it propagates to the output geometry.

The main entry point graphviz2drawio/graphviz2drawio.convert verifies that GraphViz successfully generated SVG output. When pygraphviz.AGraph.draw() returns None, the function raises UnableToParseGraphError(graph) to indicate the input DOT file is invalid or GraphViz execution failed.

Path Parsing Protection

When graphviz2drawio/mx/RectFactory.rect_from_svg_path encounters malformed path data, the resulting CouldNotParsePathError(path_d) provides the exact offending path string, enabling precise debugging of SVG generation issues.

Top-Level CLI Error Handling

The command-line interface in graphviz2drawio/__main__.py implements comprehensive error handling to surface user-friendly messages while maintaining diagnostic detail.

Conversion Wrapper

The convert() call is wrapped in a try/except block that handles specific encoding and unexpected failures:

try:
    output = convert(to_convert, program)
except UnicodeDecodeError:
    # Automatic UTF-8 retry for Windows-specific encoding issues

    return _convert_file(...)
except Exception:
    _write_stderr_message(str(to_convert))
    raise

This structure catches UnicodeDecodeError to implement an automatic fallback to UTF-8 encoding (lines 46–53). For all other exceptions, it invokes _write_stderr_message (lines 24–31) to print a formatted error block containing the Python version, library version, and input file path before re-raising the exception to ensure a non-zero exit status.

Argument Validation

The _validate_args function performs pre-flight checks on command-line arguments, verifying mutually exclusive options like --stdout and --outfile, and confirming required input files exist. Upon validation failure, it prints a clear error message and calls sys.exit(1) (lines 16–23).

Graceful Degradation for Edge Cases

Not all errors halt execution. The utility function adjust_color_opacity in graphviz2drawio/mx/utils.py demonstrates graceful degradation by wrapping hex color parsing in a try/except block:

try:
    # Parse and adjust hex color opacity

    ...
except ValueError:
    return hex_string  # Return original on parse failure

When a color string cannot be parsed as valid hexadecimal, the function returns the original string rather than crashing, allowing the conversion to continue with potentially malformed but non-critical styling attributes.

Code Examples

Catching Specific Conversion Errors

from graphviz2drawio.models.Errors import MissingTitleError, GdValueError
from graphviz2drawio.graphviz2drawio import convert
from pygraphviz import AGraph

dot = "digraph { a -> b }"
graph = AGraph(string=dot)

try:
    mx_xml = convert(graph)
except MissingTitleError as exc:
    print(f"Title missing in SVG element: {exc}")
except GdValueError as exc:
    print(f"Graph conversion failed: {exc}")

Handling CLI Errors Programmatically

import subprocess

result = subprocess.run(
    ["graphviz2drawio", "example.dot"],
    capture_output=True,
    text=True,
)

if result.returncode != 0:
    print("Conversion failed:")
    print(result.stderr)  # Contains formatted error from _write_stderr_message

Validating Bézier Parameters

from graphviz2drawio.mx.bezier import subdivide
from graphviz2drawio.models.Errors import InvalidBezierParameterError

try:
    left, right = subdivide(p1, c1, c2, p2, t=1.5)
except InvalidBezierParameterError as exc:
    print(f"Invalid curve parameter: {exc}")

Summary

  • Custom exception hierarchy centered on GdValueError in graphviz2drawio/models/Errors.py enables both broad and granular error catching
  • Defensive validation throughout NodeFactory, SvgParser, and bezier modules raises specific exceptions like MissingIdentifiersError and InvalidBezierParameterError at the point of failure
  • CLI resilience in graphviz2drawio/__main__.py provides automatic UTF-8 fallback for encoding errors and structured stderr reporting via _write_stderr_message
  • Graceful degradation in utility functions like adjust_color_opacity allows conversion to continue despite malformed non-critical data
  • Pre-flight validation via _validate_args ensures argument errors are caught before conversion begins with clear sys.exit(1) termination

Frequently Asked Questions

What is the base exception class for all graphviz2drawio errors?

All custom exceptions in graphviz2drawio inherit from GdValueError, defined in graphviz2drawio/models/Errors.py. This base class allows you to catch any conversion-specific error using except GdValueError: while still permitting handlers for specific subclasses like MissingTitleError or UnableToParseGraphError.

How does graphviz2drawio handle file encoding issues?

The CLI entry point in graphviz2drawio/__main__.py specifically catches UnicodeDecodeError and automatically retries the conversion using UTF-8 encoding. This handles Windows-specific encoding issues without requiring user intervention. If the retry fails, the error propagates to the generic exception handler which writes a detailed error message to stderr.

Can I catch all graphviz2drawio conversion errors with a single except clause?

Yes. Since all custom exceptions inherit from GdValueError, you can use a single except GdValueError as exc: clause to catch any conversion-related failure including CouldNotParsePathError, MissingIdentifiersError, and UnableToParseGraphError. This is the recommended approach for library consumers who want to handle all graphviz2drawio-specific errors uniformly.

What happens when GraphViz produces invalid or empty output?

When pygraphviz.AGraph.draw() returns None—indicating GraphViz could not render the graph—the convert() function in graphviz2drawio/graphviz2drawio.py raises UnableToParseGraphError. This provides immediate feedback that the input DOT syntax is invalid or GraphViz installation/configuration is faulty, rather than proceeding with null data.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →