{"record":{"id":"ffef33a3bec5f844","repo":"apache/beam","slug":"at-least-one-of-render-port-or-render-output-must-be","errorCode":null,"errorMessage":"At least one of --render_port or --render_output must be provided.","messagePattern":"At least one of --render_port or --render_output must be provided\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/runners/render.py","lineNumber":408,"sourceCode":"            {cmapx}\n            </div>\n          </body>\n        </html>\n    \"\"\"\n\n\nclass RenderRunner(runner.PipelineRunner):\n  # TODO(robertwb): Consider making this a runner wrapper, where live status\n  # (such as counters, stage completion status, or possibly even PCollection\n  # samples) queryable and/or displayed.  This could evolve into a full Beam\n  # UI.\n  def run_pipeline(self, pipeline_object, options):\n    return self.run_portable_pipeline(pipeline_object.to_runner_api(), options)\n\n  def run_portable_pipeline(self, pipeline_proto, options):\n    render_options = options.view_as(RenderOptions)\n    if render_options.render_port < 0 and not render_options.render_output:\n      raise ValueError(\n          'At least one of --render_port or --render_output must be provided.')\n    if render_options.log_proto:\n      _LOGGER.info(pipeline_proto)\n    renderer = PipelineRenderer(pipeline_proto, render_options)\n    try:\n      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)","sourceCodeStart":390,"sourceCodeEnd":426,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/runners/render.py#L390-L426","documentation":"The graphviz renderer requires at least one output channel: an HTTP render port or output files. run_portable_pipeline raises ValueError when --render_port is negative (disabled) and --render_output is empty. It is an early option-validation guard before rendering begins.","triggerScenarios":"Invoking the render runner (e.g. --runner=RenderRunner or beam render CLI) without setting --render_output and with --render_port left at its disabled default (<0), or explicitly passing --render_port=-1.","commonSituations":"Running 'python -m apache_beam.runners.render' with no output flags; forgetting --render_port 8099 when expecting a web view; scripts that clear render_output while disabling the port.","solutions":["Pass --render_output=path.dot (or multiple outputs) when launching the render runner","Set a valid --render_port (>= 0), e.g. --render_port 8099, to serve the graph over HTTP","Provide both if you want file and HTTP output"],"exampleFix":"# before\npython -m apache_beam.runners.render --pipeline_file=pipeline.pb  # ValueError\n# after\npython -m apache_beam.runners.render --pipeline_file=pipeline.pb --render_output=pipeline.dot","handlingStrategy":"validation","validationCode":"from apache_beam.options.pipeline_options import PipelineOptions\nopts = PipelineOptions(argv)\nr = opts.view_as(RenderOptionsLike)\nif r.render_port < 0 and not r.render_output:\n    raise SystemExit('Provide --render_port >= 0 or --render_output=FILE.dot')","typeGuard":"def render_target_configured(render_port: int, render_output) -> bool:\n    return render_port >= 0 or bool(render_output)","tryCatchPattern":"try:\n    result = pipeline.run()\nexcept ValueError as e:\n    if 'render_port or --render_output' in str(e):\n        argv += ['--render_output', 'pipeline.dot']\n        result = PipelineOptions(argv).run_pipeline(...)\n    else:\n        raise","preventionTips":["Always pass --render_output or --render_port when invoking the render runner","Default render flags in wrapper scripts for the render entry point","Add a smoke test that renders a trivial pipeline with your standard flags"],"tags":["python","apache-beam","cli","render","validation"],"backgroundTag":"missing-required-option","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T21:17:11.552Z"}