{"record":{"id":"98d1770fc794c11e","repo":"apache/beam","slug":"flags-must-be-an-iterable-of-of-strings-not-a-single-string","errorCode":null,"errorMessage":"Flags must be an iterable of of strings, not a single string.","messagePattern":"Flags must be an iterable of of strings, not a single string\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/options/pipeline_options.py","lineNumber":369,"sourceCode":"                flag names.\n                Option names: These are defined as dest in the\n                parser.add_argument() for each flag. Passing flags\n                like {no_use_public_ips: True}, for which the dest is\n                defined to a different flag name in the parser,\n                would be discarded. Instead, pass the dest of\n                the flag (dest of no_use_public_ips is use_public_ips).\n    \"\"\"\n    # Initializing logging configuration in case the user did not set it up.\n    logging.basicConfig()\n\n    # self._flags stores a list of not yet parsed arguments, typically,\n    # command-line flags. This list is shared across different views.\n    # See: view_as().\n    if isinstance(flags, str):\n      # Unfortunately a single str passes the Iterable[str] test, as it is\n      # an iterable of single characters.  This is almost certainly not the\n      # intent...\n      raise ValueError(\n          \"Flags must be an iterable of of strings, not a single string.\")\n    self._flags = flags\n\n    # Build parser that will parse options recognized by the [sub]class of\n    # PipelineOptions whose object is being instantiated.\n    parser = _BeamArgumentParser(allow_abbrev=False)\n    for cls in type(self).mro():\n      if cls == PipelineOptions:\n        break\n      elif '_add_argparse_args' in cls.__dict__:\n        cls._add_argparse_args(parser)  # type: ignore\n\n    # The _visible_options attribute will contain options that were recognized\n    # by the parser.\n    self._visible_options, _ = parser.parse_known_args(flags)\n\n    # self._all_options is initialized with overrides to flag values,\n    # provided in kwargs, and will store key-value pairs for options recognized","sourceCodeStart":351,"sourceCodeEnd":387,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/options/pipeline_options.py#L351-L387","documentation":"PipelineOptions.__init__ accepts flags as an iterable of strings; a single str technically passes Iterable[str] but iterates as characters, so it is explicitly rejected. The library raises ValueError to prevent almost-certainly unintended behavior.","triggerScenarios":"PipelineOptions('--runner=DirectRunner') — passing one flag as a bare string instead of a list.","commonSituations":"Hard-coding a single CLI flag in scripts, or building options from a string read from a config file without splitting it.","solutions":["Wrap the flags in a list: PipelineOptions(['--runner=DirectRunner']).","If starting from a single string, split it: shlex.split(flags_str).","Fix config parsing to always produce a list of strings."],"exampleFix":"# before\noptions = PipelineOptions('--runner=DataflowRunner')\n# after\nimport shlex\noptions = PipelineOptions(shlex.split('--runner=DataflowRunner'))","handlingStrategy":"type-guard","validationCode":"if isinstance(flags, str):\n    flags = shlex.split(flags)","typeGuard":"def is_flag_list(v) -> bool:\n    return isinstance(v, (list, tuple)) and all(isinstance(x, str) for x in v)","tryCatchPattern":"try:\n    opts = PipelineOptions(flags)\nexcept ValueError as e:\n    opts = PipelineOptions(shlex.split(flags))","preventionTips":["Always construct options from a list literal of flag strings.","Add a lint/check helper that rejects str inputs to options-building code."],"tags":["apache-beam","python","type-error"],"backgroundTag":"type-mismatch","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"}