{"record":{"id":"11d40bbe1ff7d827","repo":"apache/beam","slug":"element-size-fn-must-be-callable","errorCode":null,"errorMessage":"element_size_fn must be callable","messagePattern":"element_size_fn must be callable","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/transforms/util.py","lineNumber":1394,"sourceCode":"          max_batch_weight=100,\n          element_size_fn=lambda x: len(x['text']))\n  \"\"\"\n  def __init__(\n      self,\n      min_batch_size: int,\n      max_batch_size: int,\n      max_batch_weight: int,\n      element_size_fn: Optional[Callable[[Any], int]] = None):\n    if min_batch_size < 1:\n      raise ValueError(f'min_batch_size must be >= 1, got {min_batch_size}')\n    if max_batch_size < min_batch_size:\n      raise ValueError(\n          f'max_batch_size ({max_batch_size}) must be >= '\n          f'min_batch_size ({min_batch_size})')\n    if max_batch_weight < 1:\n      raise ValueError(f'max_batch_weight must be >= 1, got {max_batch_weight}')\n    if element_size_fn is not None and not callable(element_size_fn):\n      raise TypeError('element_size_fn must be callable')\n\n    self._min_batch_size = min_batch_size\n    self._max_batch_size = max_batch_size\n    self._max_batch_weight = max_batch_weight\n\n    # None means the DoFn will use its own _default_element_size method,\n    # which tries len() and warns once on TypeError before falling back to 1.\n    self._element_size_fn = element_size_fn\n\n  def expand(self, pcoll):\n    if pcoll.windowing.is_default():\n      return pcoll | ParDo(\n          _SortAndBatchElementsDoFn(\n              self._min_batch_size,\n              self._max_batch_size,\n              self._max_batch_weight,\n              self._element_size_fn))\n    return pcoll | ParDo(","sourceCodeStart":1376,"sourceCodeEnd":1412,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/transforms/util.py#L1376-L1412","documentation":"GroupIntoBatches' element_size_fn, when provided, must be callable; the constructor raises TypeError otherwise. The function computes each element's weight for batch accumulation, so a non-callable default (e.g. a constant int passed by mistake) is rejected.","triggerScenarios":"Passing element_size_fn=5 or a dict instead of a function, or passing a lambda-wannabe like `element_size_fn=lambda` syntax errors resolved to None-adjacent mistakes; also passing functools.partial results that turned out to be plain values.","commonSituations":"Confusing element_size_fn with a static element size (passing an int instead of len-like callable); accidental shadowing of a function name by a variable earlier in scope.","solutions":["Pass an actual callable, e.g. element_size_fn=lambda x: len(str(x))","If you want a constant size, wrap it: element_size_fn=lambda x: 10","Print/type-check the argument before constructing the transform"],"exampleFix":"// before\nutil.GroupIntoBatches(1, 100, 1024, element_size_fn=16)\n// after\nutil.GroupIntoBatches(1, 100, 1024, element_size_fn=lambda x: 16)","handlingStrategy":"type-guard","validationCode":"if element_size_fn is not None and not callable(element_size_fn):\n    raise TypeError('element_size_fn must be callable')","typeGuard":"def is_size_fn(v): return v is None or callable(v)","tryCatchPattern":null,"preventionTips":["Pass lambda x: ... functions, not raw ints","Check for variable shadowing of function names","Type-annotate transform parameters"],"tags":["python","apache-beam","type-error","constructor","batching"],"backgroundTag":"type-mismatch","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"}