HKUDS/Vibe-Trading · error · ValuationError

{MODEL_NAME}: max_circularity_iterations must be >= 1, got {

Error message

{MODEL_NAME}: max_circularity_iterations must be >= 1, got {max_circularity_iterations!r}

What it means

project_three_statement validates solver settings up front: max_circularity_iterations must be an integer >= 1. Zero or negative values (or a float like 0) raise ValuationError immediately, since the circularity loop would otherwise never execute.

Source

Thrown at agent/src/quantlib/valuation/threestatement.py:710

    Raises:
        MissingInputError: If ``opening`` or ``drivers`` is missing a required
            field.
        ValuationError: If the driver sequences disagree in length, are empty,
            if any opening or driver value is not a finite number, or if
            ``circularity_tolerance`` / ``balance_tolerance`` /
            ``max_circularity_iterations`` are not usable.
        BalanceSheetError: If the opening balance sheet, or any projected
            period's balance sheet, does not balance.
        ConvergenceError: If any period's interest/revolver circularity fails
            to converge within ``max_circularity_iterations``.
    """
    require_inputs(opening, OPENING_REQUIRED_FIELDS, MODEL_NAME)
    require_inputs(drivers, DRIVER_REQUIRED_FIELDS, MODEL_NAME)
    circularity_tolerance = require_positive(circularity_tolerance, "circularity_tolerance", MODEL_NAME)
    balance_tolerance = require_positive(balance_tolerance, "balance_tolerance", MODEL_NAME)
    if max_circularity_iterations < 1:
        raise ValuationError(
            f"{MODEL_NAME}: max_circularity_iterations must be >= 1, got "
            f"{max_circularity_iterations!r}"
        )

    for field in OPENING_REQUIRED_FIELDS:
        _require_finite(opening[field], f"opening {field}", MODEL_NAME)
    for field in DRIVER_REQUIRED_FIELDS:
        for index, raw in enumerate(drivers[field]):
            _require_finite(raw, f"drivers {field}[{index}]", MODEL_NAME)

    periods = _resolve_period_count(drivers)

    opening_balance_sheet = BalanceSheet(
        period=0,
        cash=float(opening["cash"]),
        net_working_capital=float(opening["net_working_capital"]),
        ppe=float(opening["ppe"]),
        revolver_balance=float(opening["revolver_balance"]),

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Set max_circularity_iterations to at least 1 (practically 50-1000).
  2. Fix the config default for the missing key.
  3. Validate the setting before the call if it comes from user input.

Example fix

# before
project_three_statement(opening, drivers, max_circularity_iterations=0)
# after
project_three_statement(opening, drivers, max_circularity_iterations=100)
Defensive patterns

Strategy: validation

Validate before calling

assert isinstance(max_circularity_iterations, int) and max_circularity_iterations >= 1

Type guard

def valid_iterations(n) -> bool:
    return isinstance(n, int) and n >= 1

Try / catch

except ValuationError as e:
    if 'max_circularity_iterations' in str(e): reset_to_default()

Prevention

When it happens

Trigger: Passing max_circularity_iterations=0, a negative number, or a config default that was never set and defaulted to 0; also passing a float such as 50.0 can slip through only if comparisons hold, so integers < 1 are the real trigger.

Common situations: Config files where the knob is optional and omitted-then-zeroed; programmatic sweeps that include 0; disabling iterations intentionally but using the wrong API.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/b016f47f21669328. Report an issue: GitHub.