{"record":{"id":"a01dff1c37852a0f","repo":"apache/beam","slug":"max-batch-size-max-batch-size-must-be-min-batch-size-min","errorCode":null,"errorMessage":"max_batch_size ({max_batch_size}) must be >= min_batch_size ({min_batch_size})","messagePattern":"max_batch_size \\((.+?)\\) must be >= min_batch_size \\((.+?)\\)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/transforms/util.py","lineNumber":1388,"sourceCode":"      # Batch with custom size function\n      data = [{'text': 'short'}, {'text': 'medium text'},\n              {'text': 'long text here'}]\n      batched = data | SortAndBatchElements(\n          min_batch_size=1,\n          max_batch_size=10,\n          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(","sourceCodeStart":1370,"sourceCodeEnd":1406,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/transforms/util.py#L1370-L1406","documentation":"GroupIntoBatches parameters require max_batch_size >= min_batch_size; the constructor raises ValueError naming both values when the ordering is violated. It fires immediately at transform construction time.","triggerScenarios":"Constructing util.GroupIntoBatches with max_batch_size smaller than min_batch_size, e.g. GroupIntoBatches(min_batch_size=50, max_batch_size=10, ...) or values swapped when parameterized from config.","commonSituations":"Swapping arguments in positional/keyword order; independent config knobs that are validated separately and never cross-checked; tuning scripts shrinking max_batch_size below the fixed min.","solutions":["Ensure max_batch_size >= min_batch_size at the call site","Clamp programmatically: max_batch_size = max(max_batch_size, min_batch_size)","Add cross-field validation where the two values are read from config"],"exampleFix":"// before\nutil.GroupIntoBatches(min_batch_size=50, max_batch_size=10, max_batch_weight=1000)\n// after\nmin_bs = 50\nmax_bs = max(10, min_bs)\nutil.GroupIntoBatches(min_batch_size=min_bs, max_batch_size=max_bs, max_batch_weight=1000)","handlingStrategy":"validation","validationCode":"if max_batch_size < min_batch_size:\n    raise ValueError('max_batch_size must be >= min_batch_size')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Cross-validate min/max pairs at config load time","Clamp max to min programmatically when tuning","Use keyword arguments to avoid argument-order swaps"],"tags":["python","apache-beam","validation","constructor","batching"],"backgroundTag":"invalid-argument-value","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"}