apache/beam · error · IllegalArgumentException

targetBatchDurationSecsWithFixedCost

Error message

targetBatchDurationSecsWithFixedCost (%f) must be positive

What it means

BatchConfig.validate rejected targetBatchDurationSecsWithFixedCost because it was <= 0. This variant expresses the target batching duration split into a fixed per-batch cost plus a per-element cost; a non-positive total makes batch sizing unsolvable, so the builder refuses it during build().

Solutions

  1. Pass a positive seconds value, or leave unset (-1 default)
  2. Coerce 0/negative config values to unset before building
  3. Validate at config load

Example fix

// before
.withTargetBatchDurationWithFixedCost(0)
// after
.withTargetBatchDurationWithFixedCost(0.5) // or omit
Defensive patterns

Strategy: validation

Validate before calling

if (d != -1 && d <= 0) throw new IllegalArgumentException("targetBatchDurationSecsWithFixedCost must be positive or -1 (unset), got " + d);

Try / catch

try {
  return builder.withTargetBatchDurationWithFixedCost(d);
} catch (IllegalArgumentException e) {
  LOG.error("Fixed-cost batch duration must be positive or unset", e); throw e;
}

Prevention

When it happens

Trigger: Calling withTargetBatchDurationWithFixedCost(x) with x <= 0 and x != -1 (e.g. 0 or -0.5) then build().

Common situations: Config value 0 reaching the builder; using -1 intending 'unset' is fine, but other negatives fail; unit conversion producing 0.0 for very small durations.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/e713034a58ba0828. Report an issue: GitHub.

Appendix: source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/BatchElements.java:259

        if (minBatchSize > maxBatchSize) {
          throw new IllegalArgumentException(
              String.format(
                  "Minimum (%d) must not be greater than maximum (%d)",
                  minBatchSize, maxBatchSize));
        }
        if (!(targetBatchOverhead > 0 && targetBatchOverhead <= 1)) {
          throw new IllegalArgumentException(
              String.format(
                  "targetBatchOverhead (%f) must be between 0 and 1", targetBatchOverhead));
        }
        if (targetBatchDurationSecs <= 0) {
          throw new IllegalArgumentException(
              String.format(
                  "targetBatchDurationSecs (%f) must be positive", targetBatchDurationSecs));
        }
        if (targetBatchDurationSecsWithFixedCost != -1
            && targetBatchDurationSecsWithFixedCost <= 0) {
          throw new IllegalArgumentException(
              String.format(
                  "targetBatchDurationSecsWithFixedCost (%f) must be positive",
                  targetBatchDurationSecsWithFixedCost));
        }
      }
    }
  }

  static class BatchSizeEstimator implements Serializable {
    private List<long[]> data = new ArrayList<>();
    private final BatchConfig config;
    private @Nullable Integer replayLastBatchSize = null; // null = no replay pending
    private final Map<Integer, Integer>
        batchSizeNumSeen; // tracks how many times each batch size seen
    private boolean ignoreNextTiming = false;
    private final Random random;

    private static final int MAX_DATA_POINTS = 100;

View on GitHub (pinned to 12126d8942)