{"record":{"id":"266dd3cb8b54096a","repo":"apache/beam","slug":"graphviz-dot-executable-not-available-for-serving","errorCode":null,"errorMessage":"Graphviz dot executable not available for serving","messagePattern":"Graphviz dot executable not available for serving","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/runners/render.py","lineNumber":432,"sourceCode":"      subprocess.run(['dot', '-V'], capture_output=True, check=True)\n    except FileNotFoundError as exn:\n      # If dot is not available, we can at least output the raw .dot files.\n      dot_files = [\n          output for output in render_options.render_output\n          if output.endswith('.dot')\n      ]\n      for output in dot_files:\n        with open(output, 'w') as fout:\n          fout.write(renderer.to_dot())\n          _LOGGER.info(\"Wrote pipeline as %s\", output)\n\n      non_dot_files = set(render_options.render_output) - set(dot_files)\n      if non_dot_files:\n        raise RuntimeError(\n            \"Graphviz dot executable not available \"\n            f\"for rendering non-dot output files {non_dot_files}\") from exn\n      elif render_options.render_port >= 0:\n        raise RuntimeError(\n            \"Graphviz dot executable not available for serving\") from exn\n\n      return RenderPipelineResult(None)\n\n    renderer.page()\n\n    if render_options.render_port >= 0:\n      # TODO: If this gets more complex, we could consider taking on a\n      # framework like Flask as a dependency.\n      class RequestHandler(http.server.BaseHTTPRequestHandler):\n        def do_GET(self):\n          parts = urllib.parse.urlparse(self.path)\n          args = urllib.parse.parse_qs(parts.query)\n          renderer.update(**args)\n\n          if parts.path == '/':\n            response = renderer.page()\n          elif parts.path == '/render':","sourceCodeStart":414,"sourceCodeEnd":450,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/runners/render.py#L414-L450","documentation":"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.","triggerScenarios":"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.","commonSituations":"Docker/CI images lacking graphviz while attempting the interactive render web UI; PATH not containing dot despite graphviz being installed elsewhere.","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"],"exampleFix":"# before\n--render_port 8099   # host without graphviz -> RuntimeError\n# after\napt-get install -y graphviz && python -m apache_beam.runners.render ... --render_port 8099","handlingStrategy":"fallback","validationCode":"import shutil\nif serve_port >= 0 and shutil.which('dot') is None:\n    raise SystemExit('Graphviz required for --render_port serving; install graphviz or drop --render_port')","typeGuard":"def can_serve_render(render_port: int) -> bool:\n    import shutil\n    return render_port < 0 or shutil.which('dot') is not None","tryCatchPattern":"try:\n    result = pipeline.run()\nexcept RuntimeError as e:\n    if 'not available for serving' in str(e):\n        rerun_without_port(render_output='pipeline.dot')  # file fallback\n    else:\n        raise","preventionTips":["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"],"tags":["python","apache-beam","graphviz","render","serving"],"backgroundTag":"command-not-found","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}