{"record":{"id":"392ac098a0b83f2a","repo":"apache/beam","slug":"partitionfn-yielded-a-type-partition-name-when-it-should","errorCode":null,"errorMessage":"PartitionFn yielded a '{type(partition).__name__}' when it should only yield integers","messagePattern":"PartitionFn yielded a '(.+?)' when it should only yield integers","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/transforms/core.py","lineNumber":3832,"sourceCode":"\n  When apply()d, a Partition() PTransform requires the following:\n\n  Args:\n    partitionfn: a PartitionFn, or a callable with the signature described in\n      CallableWrapperPartitionFn.\n    n: number of output partitions.\n\n  The result of this PTransform is a simple list of the output PCollections\n  representing each of n partitions, in order.\n  \"\"\"\n  class ApplyPartitionFnFn(DoFn):\n    \"\"\"A DoFn that applies a PartitionFn.\"\"\"\n    def process(self, element, partitionfn, n, *args, **kwargs):\n      partition = partitionfn.partition_for(element, n, *args, **kwargs)\n      import numbers\n      if isinstance(partition,\n                    bool) or not isinstance(partition, numbers.Integral):\n        raise ValueError(\n            f\"PartitionFn yielded a '{type(partition).__name__}' \"\n            \"when it should only yield integers\")\n      if not 0 <= int(partition) < n:\n        raise ValueError(\n            'PartitionFn specified out-of-bounds partition index: '\n            '%d not in [0, %d)' % (partition, n))\n      # Each input is directed into the output that corresponds to the\n      # selected partition.\n      yield pvalue.TaggedOutput(str(partition), element)\n\n  def make_fn(self, fn, has_side_inputs):\n    return fn if isinstance(fn, PartitionFn) else CallableWrapperPartitionFn(fn)\n\n  def expand(self, pcoll):\n    n = int(self.args[0])\n    args, kwargs = util.insert_values_in_args(\n        self.args, self.kwargs, self.side_inputs)\n    return pcoll | ParDo(self.ApplyPartitionFnFn(), self.fn, *args, **","sourceCodeStart":3814,"sourceCodeEnd":3850,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/transforms/core.py#L3814-L3850","documentation":"Raised inside Partition's DoFn process() when the user-supplied PartitionFn.partition_for() returns something that is not an integral number (and booleans are explicitly rejected). Beam requires each partition index to be an int so it can route the element to a tagged output. The f-string includes the actual returned type name to aid debugging.","triggerScenarios":"A custom PartitionFn whose partition_for returns a float (e.g. element % 2.0), a numpy integer-like type not registered as numbers.Integral (rare), a bool (True/False), or returns None/str on some code path.","commonSituations":"Using floor division that yields a float (x // 2.0), returning a numpy.int64 from numpy-based logic in environments where it is accepted (accepted) vs a numpy.float64 (rejected), accidentally returning True/False from a comparison-based partitioner, or a partition function with an unhandled branch returning None.","solutions":["Ensure partition_for returns a plain Python int: return int(index).","Replace float arithmetic with integer arithmetic (use // with int operands, not floats).","Add explicit bool handling: comparisons like x > 0 yield bool; convert to int and use distinct branch logic.","Cover all input cases in partition_for so no path returns None."],"exampleFix":"// before\nclass MyFn(beam.PartitionFn):\n  def partition_for(self, elem, n):\n    return hash(elem.key) % n / 1.0  # float\n// after\nclass MyFn(beam.PartitionFn):\n  def partition_for(self, elem, n):\n    return int(hash(elem.key) % n)","handlingStrategy":"validation","validationCode":"idx = partitionfn.partition_for(elem, n)\nassert isinstance(idx, int) and not isinstance(idx, bool), f'partition_for returned {type(idx).__name__}'","typeGuard":"def is_valid_partition(v):\n    return isinstance(v, int) and not isinstance(v, bool)","tryCatchPattern":"try:\n    pc | beam.Partition(fn, n)\nexcept ValueError as e:\n    log.error('PartitionFn returned non-integer: %s', e)","preventionTips":["Use integer arithmetic (//, %) in partition_for","Convert results with int()","Avoid comparison results (bools) as indices","Test partition_for over representative elements before running the pipeline"],"tags":["python","apache-beam","partitionfn","type-mismatch"],"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"}