{"record":{"id":"7e60ec5859df7e49","repo":"apache/beam","slug":"found-more-than-one-renderer-for-option-s","errorCode":null,"errorMessage":"Found more than one renderer for option: %s","messagePattern":"Found more than one renderer for option: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/runners/interactive/display/pipeline_graph_renderer.py","lineNumber":126,"sourceCode":"      exists = subprocess.call(['where', 'dot.exe']) == 0\n    else:\n      exists = subprocess.call(['which', 'dot']) == 0\n\n    if exists:\n      option = 'graph'\n    else:\n      option = 'text'\n\n  renderer = [\n      r for r in PipelineGraphRenderer.get_all_subclasses()\n      if option == r.option()\n  ]\n  if len(renderer) == 0:\n    raise ValueError()\n  elif len(renderer) == 1:\n    return renderer[0]()\n  else:\n    raise ValueError('Found more than one renderer for option: %s', option)\n","sourceCodeStart":108,"sourceCodeEnd":127,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/runners/interactive/display/pipeline_graph_renderer.py#L108-L127","documentation":"get_renderer() raises this ValueError when more than one PipelineGraphRenderer subclass claims the same option(). This is an internal registration invariant violation: option strings are expected to uniquely identify a renderer.","triggerScenarios":"Defining a custom renderer subclass whose option() returns a string already used by a built-in renderer (e.g. duplicate 'graphviz'), then calling get_renderer(option) which finds two matches.","commonSituations":"A user copies a built-in renderer class to customize it but forgets to change option(); a third-party extension registers a conflicting option; Beam upgrade introduces a renderer colliding with a locally defined one.","solutions":["Change the duplicate option() string in your custom renderer subclass to a unique value.","Remove or rename the redundant renderer subclass so only one claims each option.","Audit all PipelineGraphRenderer subclasses (get_all_subclasses) and their option() values for collisions.","Check recently installed Beam extensions/plugins that may register conflicting renderers."],"exampleFix":"// before\nclass MyRenderer(PipelineGraphRenderer):\n  @staticmethod\n  def option():\n    return 'graphviz'  # collides with built-in\n// after\nclass MyRenderer(PipelineGraphRenderer):\n  @staticmethod\n  def option():\n    return 'my-graphviz'","handlingStrategy":"validation","validationCode":"from collections import Counter\nfrom apache_beam.runners.interactive.display.pipeline_graph_renderer import PipelineGraphRenderer\noptions = [r.option() for r in PipelineGraphRenderer.get_all_subclasses()]\ndupes = [o for o, c in Counter(options).items() if c > 1]\nassert not dupes, f'Duplicate renderer options: {dupes}'","typeGuard":null,"tryCatchPattern":"try:\n    renderer = get_renderer(option)\nexcept ValueError as e:\n    if 'more than one renderer' in str(e) or 'Found more than one' in str(e):\n        renderer = fix_duplicate_registration(option)\n    else:\n        raise","preventionTips":["Give custom renderer subclasses unique option() strings","Never copy a built-in renderer class without renaming its option","Audit get_all_subclasses() option values after adding renderers","Avoid installing third-party extensions that re-register options"],"tags":["python","value-error","internal-invariant","apache-beam"],"backgroundTag":"internal-invariant-violation","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"}