mvanhorn/last30days-skill · error · SystemExit

[Competitors] --competitors must be >= {COMPETITORS_MIN} (go

Error message

[Competitors] --competitors must be >= {COMPETITORS_MIN} (got {count}).\n

What it means

When --competitors N is given without a list, the resolver enforces COMPETITORS_MIN <= N: values below the minimum abort with SystemExit(2), while values above COMPETITORS_MAX are only clamped with a warning (asymmetric on purpose — too few comparisons is statistically useless, too many is just capped).

Source

Thrown at skills/last30days/scripts/last30days.py:1036

            sys.stderr.write(
                f"[Competitors] --competitors={competitors_flag} ignored; using "
                f"{count} entries from --competitors-list.\n"
            )
        if count > COMPETITORS_MAX:
            sys.stderr.write(
                f"[Competitors] --competitors-list has {count} entries, clamping to {COMPETITORS_MAX}.\n"
            )
            explicit_list = explicit_list[:COMPETITORS_MAX]
            count = COMPETITORS_MAX
        return True, count, explicit_list

    if flag_present:
        count = competitors_flag
        if count < COMPETITORS_MIN:
            sys.stderr.write(
                f"[Competitors] --competitors must be >= {COMPETITORS_MIN} (got {count}).\n"
            )
            raise SystemExit(2)
        if count > COMPETITORS_MAX:
            sys.stderr.write(
                f"[Competitors] --competitors={count} exceeds max {COMPETITORS_MAX}; clamping.\n"
            )
            count = COMPETITORS_MAX
        return True, count, []

    # plan_present alone: enable; peers filled by apply_vs_competitor_routing.
    return True, 0, []


def _missing_sources_for_promo(diag: dict[str, object]) -> str | None:
    available = set(diag.get("available_sources") or [])
    missing = []
    if "reddit" not in available:
        missing.append("reddit")
    if "x" not in available:
        missing.append("x")

View on GitHub (pinned to c7460f6114)

Solutions

  1. Pass a count within [COMPETITORS_MIN, COMPETITORS_MAX] (check the constants near the resolver; use at least 2).
  2. For automatic peer discovery without an explicit count, use --competitors-plan or the plan-present path instead.
  3. Clamp computed counts in the caller: max(count, 2) or skip the run when discovery found fewer peers than the minimum.

Example fix

# before
--competitors 1

# after
--competitors 3
Defensive patterns

Strategy: validation

Validate before calling

count = max(int(count_arg), 0)
if count < COMPETITORS_MIN:
    raise ValueError(f'--competitors must be >= {COMPETITORS_MIN}')
count = min(count, COMPETITORS_MAX)

Prevention

When it happens

Trigger: --competitors 0 or --competitors 1 (if COMPETITORS_MIN is 2+); passing a negative number; a computed count (len of discovered peers) collapsing to 0/1 after filtering.

Common situations: Scripts deriving the count from a variable that can be 0 or 1; misunderstanding that 0 does not mean 'auto'.

Related errors


AI-assisted analysis of mvanhorn/last30days-skill@c7460f6114 (2026-08-15). Data as JSON: /api/errors/6d94698311a1c9b3. Report an issue: GitHub.