apache/beam · error · RuntimeError
Graphviz dot executable not available for serving
Error message
Graphviz dot executable not available for serving
What it means
If the Graphviz 'dot' executable is missing and --render_port was requested, the renderer cannot serve the pipeline graph over HTTP and raises RuntimeError chained from the original 'dot -V' failure. Rendering to a live page requires dot even though only serving was requested.
Solutions
- Install Graphviz (apt-get install graphviz / brew install graphviz) and confirm 'dot -V' works
- Add graphviz's install location to PATH
- Drop --render_port and write a .dot file instead if graphviz cannot be installed
Example fix
# before --render_port 8099 # host without graphviz -> RuntimeError # after apt-get install -y graphviz && python -m apache_beam.runners.render ... --render_port 8099
Defensive patterns
Strategy: fallback
Validate before calling
import shutil
if serve_port >= 0 and shutil.which('dot') is None:
raise SystemExit('Graphviz required for --render_port serving; install graphviz or drop --render_port') Type guard
def can_serve_render(render_port: int) -> bool:
import shutil
return render_port < 0 or shutil.which('dot') is not None Try / catch
try:
result = pipeline.run()
except RuntimeError as e:
if 'not available for serving' in str(e):
rerun_without_port(render_output='pipeline.dot') # file fallback
else:
raise Prevention
- Bake graphviz into render-serving container images
- Check PATH includes the graphviz bin directory
- Offer a --render_output file path as the default fallback in launch wrappers
When it happens
Trigger: Launching run_portable_pipeline with --render_port >= 0 (e.g. --render_port 8099) on a host where the graphviz 'dot' binary is absent, so subprocess 'dot -V' check fails.
Common situations: Docker/CI images lacking graphviz while attempting the interactive render web UI; PATH not containing dot despite graphviz being installed elsewhere.
Related errors
- Graphviz dot executable not available for rendering non-dot…
- At least one of --render_port or --render_output must be…
- A BigQuery table or a query must be specified
- A cluster_identifier should be Optional[Union[str…
- A context manager constructor (not a fully constructed…
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/266dd3cb8b54096a.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/python/apache_beam/runners/render.py:432
subprocess.run(['dot', '-V'], capture_output=True, check=True)
except FileNotFoundError as exn:
# If dot is not available, we can at least output the raw .dot files.
dot_files = [
output for output in render_options.render_output
if output.endswith('.dot')
]
for output in dot_files:
with open(output, 'w') as fout:
fout.write(renderer.to_dot())
_LOGGER.info("Wrote pipeline as %s", output)
non_dot_files = set(render_options.render_output) - set(dot_files)
if non_dot_files:
raise RuntimeError(
"Graphviz dot executable not available "
f"for rendering non-dot output files {non_dot_files}") from exn
elif render_options.render_port >= 0:
raise RuntimeError(
"Graphviz dot executable not available for serving") from exn
return RenderPipelineResult(None)
renderer.page()
if render_options.render_port >= 0:
# TODO: If this gets more complex, we could consider taking on a
# framework like Flask as a dependency.
class RequestHandler(http.server.BaseHTTPRequestHandler):
def do_GET(self):
parts = urllib.parse.urlparse(self.path)
args = urllib.parse.parse_qs(parts.query)
renderer.update(**args)
if parts.path == '/':
response = renderer.page()
elif parts.path == '/render':View on GitHub (pinned to 12126d8942)