{"record":{"id":"df3a5a2f7e3460d1","repo":"apache/beam","slug":"namespaces-must-be-an-iterable-not-a-string","errorCode":null,"errorMessage":"Namespaces must be an iterable, not a string","messagePattern":"Namespaces must be an iterable, not a string","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/metrics/metric.py","lineNumber":373,"sourceCode":"    return self.with_name(name).with_namespace(namespace)\n\n  def with_name(self, name: str) -> 'MetricsFilter':\n    return self.with_names([name])\n\n  def with_names(self, names: Iterable[str]) -> 'MetricsFilter':\n    if isinstance(names, str):\n      raise ValueError('Names must be a collection, not a string')\n\n    self._names.update(names)\n    return self\n\n  def with_namespace(self, namespace: Union[type, str]) -> 'MetricsFilter':\n    return self.with_namespaces([namespace])\n\n  def with_namespaces(\n      self, namespaces: Iterable[Union[type, str]]) -> 'MetricsFilter':\n    if isinstance(namespaces, str):\n      raise ValueError('Namespaces must be an iterable, not a string')\n\n    self._namespaces.update([Metrics.get_namespace(ns) for ns in namespaces])\n    return self\n\n  def with_step(self, step: str) -> 'MetricsFilter':\n    return self.with_steps([step])\n\n  def with_steps(self, steps: Iterable[str]) -> 'MetricsFilter':\n    if isinstance(steps, str):\n      raise ValueError('Steps must be an iterable, not a string')\n\n    self._steps.update(steps)\n    return self\n\n\nclass Lineage:\n  \"\"\"Standard collection of metrics used to record source and sinks information\n  for lineage tracking.\"\"\"","sourceCodeStart":355,"sourceCodeEnd":391,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/metrics/metric.py#L355-L391","documentation":"MetricsFilter.with_namespaces() requires an iterable of namespaces; passing a single string raises ValueError so that the string is not silently split into characters. Use with_namespace for a single value.","triggerScenarios":"MetricsFilter().with_namespaces('myns') or with_namespaces(SomeClass) — a str (or other non-iterable) instead of a collection of namespaces; reached indirectly through with_namespace only if the caller wraps wrongly.","commonSituations":"Querying pipeline metrics and passing one namespace directly; namespaces built from class types being passed without wrapping.","solutions":["Wrap in a list: with_namespaces(['myns']) or with_namespaces([MyClass]).","Use with_namespace('myns') for a single namespace.","Ensure the argument is a list/set/generator/tuple, not str/bytes."],"exampleFix":"- MetricsFilter().with_namespaces('myns')\n+ MetricsFilter().with_namespaces(['myns'])","handlingStrategy":"validation","validationCode":"namespaces = [ns] if isinstance(ns, (str, type)) else list(ns)\nfilter_ = MetricsFilter().with_namespaces(namespaces)","typeGuard":"def as_namespace_list(namespaces):\n    return [namespaces] if isinstance(namespaces, (str, type)) else list(namespaces)","tryCatchPattern":"try:\n    f = MetricsFilter().with_namespaces(namespaces)\nexcept ValueError:\n    f = MetricsFilter().with_namespaces([namespaces])","preventionTips":["Use with_namespace() for single values.","Remember namespaces may be classes or strings — both still need wrapping in a list.","Normalize list-vs-scalar inputs before building filters."],"tags":["python","apache-beam","metrics-filter","argument-validation"],"backgroundTag":"invalid-argument-format","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}