multica-ai/multica · error

--batch-size must be positive

Error message

--batch-size must be positive

What it means

Config validation error: --batch-size was supplied as zero or negative (or its default left uninitialized in a non-flag context). The batch size controls how many task_usage rows each UPDATE round touches, so the tool requires a positive value before proceeding.

Source

Thrown at server/cmd/backfill_codex_usage_cache/main.go:172

		"to", rollupTo.Format(time.RFC3339),
		"rows_touched", rollupRows)
	return nil
}

func (cfg *config) parseAndValidate(now time.Time) error {
	if cfg.cutoffRaw == "" {
		return fmt.Errorf("--cutoff is required; use the hosted deployment time of the Codex usage normalization fix")
	}
	cutoff, err := time.Parse(time.RFC3339, cfg.cutoffRaw)
	if err != nil {
		return fmt.Errorf("parse --cutoff as RFC3339: %w", err)
	}
	cutoff = cutoff.UTC()
	if !cutoff.Before(now) {
		return fmt.Errorf("--cutoff must be before now; refusing a future cutoff because it could double-subtract already-normalized rows")
	}
	if cfg.batchSize <= 0 {
		return fmt.Errorf("--batch-size must be positive")
	}
	cfg.cutoff = cutoff
	return nil
}

func loadDryRunSummary(ctx context.Context, pool *pgxpool.Pool, cfg config) ([]summaryRow, totals, error) {
	const query = `
SELECT
    a.workspace_id::text AS workspace_id,
    (tu.created_at AT TIME ZONE 'UTC')::date::text AS date_utc,
    COUNT(*)::bigint AS rows,
    COALESCE(SUM(tu.input_tokens), 0)::bigint AS input_before,
    COALESCE(SUM(GREATEST(tu.input_tokens - tu.cache_read_tokens, 0)), 0)::bigint AS input_after,
    COALESCE(SUM(tu.input_tokens - GREATEST(tu.input_tokens - tu.cache_read_tokens, 0)), 0)::bigint AS overcount,
    COUNT(*) FILTER (WHERE tu.input_tokens < tu.cache_read_tokens)::bigint AS clamped_rows,
    MIN(tu.created_at) AS min_created_at,
    MAX(tu.created_at) AS max_created_at
FROM task_usage tu

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Pass a positive integer, e.g. --batch-size 5000.
  2. Default the variable in the script: BATCH=${BATCH:-5000} before invoking.
  3. Tune the value against database load; there is no need for extreme sizes since the tool loops until done.

Example fix

# before
BATCH=
./backfill_codex_usage_cache --cutoff ... --batch-size $BATCH
# --batch-size must be positive

# after
BATCH=${BATCH:-5000}
./backfill_codex_usage_cache --cutoff 2026-06-01T12:00:00Z --batch-size $BATCH --execute
Defensive patterns

Strategy: validation

Validate before calling

BATCH=${BATCH:-5000}
case "$BATCH" in (*[!0-9]*|'') echo '--batch-size must be a positive integer'; exit 1;; esac
./backfill_codex_usage_cache --cutoff "$CUTOFF" --batch-size "$BATCH"

Prevention

When it happens

Trigger: Passing --batch-size 0 or a negative number; an wrapper script passing an unset shell variable that expands to nothing/0.

Common situations: Parameterized runbooks interpolating an empty variable (--batch-size $BATCH with BATCH unset); attempting 'unbatched' mode with 0; typo'd negative value.

Related errors


AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15). Data as JSON: /api/errors/933c01631ab2e75d. Report an issue: GitHub.