{"record":{"id":"3b17a210d528ef0f","repo":"apache/iceberg","slug":"cannot-split-a-task-which-is-already-split","errorCode":null,"errorMessage":"Cannot split a task which is already split","messagePattern":"Cannot split a task which is already split","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/BaseFileScanTask.java","lineNumber":163,"sourceCode":"\n    @Override\n    public long sizeBytes() {\n      return len + deletesSizeBytes();\n    }\n\n    @Override\n    public int filesCount() {\n      return fileScanTask.filesCount();\n    }\n\n    @Override\n    public Expression residual() {\n      return fileScanTask.residual();\n    }\n\n    @Override\n    public Iterable<FileScanTask> split(long splitSize) {\n      throw new UnsupportedOperationException(\"Cannot split a task which is already split\");\n    }\n\n    @Override\n    public boolean canMerge(ScanTask other) {\n      if (other instanceof SplitScanTask) {\n        SplitScanTask that = (SplitScanTask) other;\n        return file().equals(that.file()) && offset + len == that.start();\n      } else {\n        return false;\n      }\n    }\n\n    @Override\n    public SplitScanTask merge(ScanTask other) {\n      SplitScanTask that = (SplitScanTask) other;\n      // don't use deletesSizeBytes() here so that deletesSizeBytes is only calculated once after\n      // merging rather than for each task before merging\n      return new SplitScanTask(offset, len + that.length(), fileScanTask, deletesSizeBytes);","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/BaseFileScanTask.java#L145-L181","documentation":"SplitScanTask (and CombinedScanTask wrappers) represent a task that has already been divided by split size, so calling split() on it again is meaningless. Iceberg throws UnsupportedOperationException to enforce the one-level-split invariant in scan planning. Once split, a task can only be merged with others or executed.","triggerScenarios":"Calling split(splitSize) on a FileScanTask returned by another split() call, e.g. re-splitting results from TableScan.planTasks()/planFiles() that produced SplitScanTask instances.","commonSituations":"Custom scan-planning or task-distribution code that iterates planned tasks and calls split() defensively; frameworks that re-partition tasks across executors after planning.","solutions":["Check task type before splitting: only call split on base file/scan tasks, not SplitScanTask/CombinedScanTask","Use the task's existing length() to distribute work instead of re-splitting","If merging is needed instead, use canMerge/merge or wrap tasks via CombinedScanTask"],"exampleFix":"// before\nfor (FileScanTask task : scan.planFiles()) {\n  tasks.addAll(task.split(targetSize)); // throws for already-split tasks\n}\n// after\nfor (FileScanTask task : scan.planFiles()) {\n  if (!(task instanceof SplitScanTask)) {\n    tasks.addAll(task.split(targetSize));\n  } else {\n    tasks.add(task);\n  }\n}","handlingStrategy":"type-guard","validationCode":"boolean splittable = !(task instanceof SplitScanTask) && !(task instanceof CombinedScanTask);","typeGuard":"if (task instanceof SplitScanTask || task instanceof CombinedScanTask) { /* already split/combined: use as-is */ } else { task.split(splitSize); }","tryCatchPattern":"try { result = task.split(splitSize); } catch (UnsupportedOperationException e) { result = Collections.singletonList(task); }","preventionTips":["Treat split() results as terminal; never call split on planned task output","Check instanceof before splitting tasks from heterogeneous sources","Handle CombinedScanTask and SplitScanTask explicitly in task-distribution code"],"tags":["scan-planning","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}