{"record":{"id":"9438330e8f6f85bb","repo":"apache/beam","slug":"num-splits-must-be-1-got-d","errorCode":null,"errorMessage":"num_splits must be > 1, got: %d","messagePattern":"num_splits must be > 1, got: (.+?)","errorType":"exception","errorClass":"SplitNotPossibleError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/io/gcp/datastore/v1new/query_splitter.py","lineNumber":72,"sourceCode":"  gather random split points for a query.\n\n  Note: This implementation is derived from the java query splitter in\n  https://github.com/GoogleCloudPlatform/google-cloud-datastore/blob/master/java/datastore/src/main/java/com/google/datastore/v1/client/QuerySplitterImpl.java\n\n  Args:\n    client: the datastore client.\n    query: the query to split.\n    num_splits: the desired number of splits.\n\n  Returns:\n    A list of split queries, of a max length of `num_splits`\n\n  Raises:\n    QuerySplitterError: if split could not be performed owing to query or split\n      parameters.\n  \"\"\"\n  if num_splits <= 1:\n    raise SplitNotPossibleError('num_splits must be > 1, got: %d' % num_splits)\n  validate_split(query)\n\n  splits = []\n  client_scatter_keys = _get_scatter_keys(client, query, num_splits)\n  last_client_key = None\n  for next_client_key in _get_split_key(client_scatter_keys, num_splits):\n    splits.append(_create_split(last_client_key, next_client_key, query))\n    last_client_key = next_client_key\n\n  splits.append(_create_split(last_client_key, None, query))\n  return splits\n\n\ndef validate_split(query):\n  \"\"\"\n  Verifies that the given query can be properly scattered.\n\n  Note that equality and ancestor filters are allowed, however they may result","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/io/gcp/datastore/v1new/query_splitter.py#L54-L90","documentation":"Datastore query splitting (get_splits) requires num_splits > 1 because splitting produces boundaries between at least two regions; asking for 1 (or fewer, or negative) splits is meaningless, so SplitNotPossibleError (a QuerySplitterError) is raised before any scatter-query work.","triggerScenarios":"Calling get_splits(client, query, num_splits) with num_splits <= 1 — e.g. passing num_splits=1, 0, or a computed value like int(total_workers / num_jobs) that evaluates to 1 or 0 when few workers/jobs are configured.","commonSituations":"Dynamic work rebalancing computing splits from remaining work counts that reach 0; configured parallelism of 1; integer division rounding down to 1 or 0 for small inputs.","solutions":["Ensure num_splits >= 2 before calling get_splits (e.g. max(2, desired_splits)).","Skip splitting entirely when only one split is needed — query without a split.","Fix the computation producing num_splits (check for zero remaining jobs/workers) and clamp it.","Catch SplitNotPossibleError and fall back to an unsplit query."],"exampleFix":"// before\nsplits = query_splitter.get_splits(client, query, num_splits)  # num_splits may be 1\n// after\nif num_splits > 1:\n    splits = query_splitter.get_splits(client, query, num_splits)\nelse:\n    splits = [query]","handlingStrategy":"validation","validationCode":"if num_splits is None or num_splits <= 1:\n    raise ValueError('num_splits must be >= 2 before calling get_splits')","typeGuard":"def can_split(num_splits):\n    return isinstance(num_splits, int) and num_splits > 1","tryCatchPattern":"try:\n    splits = query_splitter.get_splits(client, query, num_splits)\nexcept SplitNotPossibleError:\n    splits = [query]  # run unsplit","preventionTips":["Clamp computed split counts: num_splits = max(2, computed)","Guard dynamic work rebalancing against zero/negative remaining work","Beware integer division producing 0 or 1 for small worker counts","Only call the splitter when parallelism > 1"],"tags":["python","datastore","argument-validation","beam-io"],"backgroundTag":"argument-out-of-range","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"}