apache/beam · error · ValueError
Names must be a collection, not a string
Error message
Names must be a collection, not a string
What it means
MetricsFilter.with_names() requires an iterable of metric names; passing a single string raises ValueError because strings are themselves iterable and would be expanded into individual characters. This check exists to catch that classic mistake.
Source
Thrown at sdks/python/apache_beam/metrics/metric.py:362
@property
def names(self) -> frozenset[str]:
return frozenset(self._names)
@property
def namespaces(self) -> frozenset[str]:
return frozenset(self._namespaces)
def with_metric(self, metric: 'Metric') -> 'MetricsFilter':
name = metric.metric_name.name or ''
namespace = metric.metric_name.namespace or ''
return self.with_name(name).with_namespace(namespace)
def with_name(self, name: str) -> 'MetricsFilter':
return self.with_names([name])
def with_names(self, names: Iterable[str]) -> 'MetricsFilter':
if isinstance(names, str):
raise ValueError('Names must be a collection, not a string')
self._names.update(names)
return self
def with_namespace(self, namespace: Union[type, str]) -> 'MetricsFilter':
return self.with_namespaces([namespace])
def with_namespaces(
self, namespaces: Iterable[Union[type, str]]) -> 'MetricsFilter':
if isinstance(namespaces, str):
raise ValueError('Namespaces must be an iterable, not a string')
self._namespaces.update([Metrics.get_namespace(ns) for ns in namespaces])
return self
def with_step(self, step: str) -> 'MetricsFilter':
return self.with_steps([step])
View on GitHub (pinned to 12126d8942)
Solutions
- Wrap the name in a list: with_names(['my_metric']).
- Use with_name('my_metric') for a single name — it wraps automatically.
- Pass a set/tuple/generator of names if filtering multiple.
Example fix
- MetricsFilter().with_names('my_metric')
+ MetricsFilter().with_names(['my_metric'])
# or for a single name
+ MetricsFilter().with_name('my_metric') Defensive patterns
Strategy: validation
Validate before calling
names = [name] if isinstance(name, str) else list(name) filter_ = MetricsFilter().with_names(names)
Type guard
def as_name_list(names):
return [names] if isinstance(names, str) else list(names) Try / catch
try:
f = MetricsFilter().with_names(names)
except ValueError:
f = MetricsFilter().with_names([names]) Prevention
- Use with_name() for a single name, with_names() for collections.
- Never pass bare strings to plural-setter methods.
- Centralize filter construction in a helper that normalizes inputs.
When it happens
Trigger: MetricsFilter().with_names('my_metric') — a bare str instead of a list/set of names; also via with_name only when code calls with_names directly with a string.
Common situations: Filtering metrics when querying MetricResults and wrapping a single name without a list; refactoring from with_name to with_names and forgetting to wrap in a list.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Namespaces must be an iterable, not a string
- Steps must be an iterable, not a string
- Cannot specify both 'labels' and 'index'/'columns'
- num_splits must be greater than or equal 0
- source_file_names and destination_file_names should be equal
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/213a254a3fc5aa88.
Report an issue: GitHub.