numpy/numpy · error · ValueError

must be >= 0

Error message

{name} must be >= 0

What it means

Raised by the internal helper _none_or_positive_arg() in numpy/_core/arrayprint.py, which validates numeric keyword arguments to array-printing / float-formatting functions. The contract is: the value may be None (a sentinel meaning 'unset', internally mapped to -1) or a non-negative number; anything strictly negative is rejected. The {name} placeholder carries the offending argument name (e.g. 'precision', 'pad_left', 'exp_digits', 'min_digits') so the message identifies which argument was at fault.

Solutions

  1. Check the offending named argument before the call: keep it None, or clamp to max(0, value).
  2. If you intended 'unset', pass None explicitly rather than -1.
  3. For line/width wrapping use np.set_printoptions(linewidth=-1) — do not reuse that -1 for precision/pad/min_digits.

Example fix

// before
np.format_float_scientific(x, precision=width - 1)  # width == 0 -> -1
// after
np.format_float_scientific(x, precision=max(0, width - 1))
Defensive patterns

Strategy: validation

Validate before calling

def safe_pos_arg(value, name):
    if value is None:
        return None
    if value < 0:
        raise ValueError(f"{name} must be >= 0, got {value!r}")
    return value

precision = safe_pos_arg(computed_precision, 'precision')
np.format_float_scientific(x, precision=precision)

Type guard

def is_none_or_non_negative(v) -> bool:
    return v is None or (isinstance(v, (int, float)) and not isinstance(v, bool) and v >= 0)

Try / catch

try:
    np.format_float_scientific(x, precision=p)
except ValueError as e:
    if 'must be >= 0' in str(e):
        p = max(0, p) if p is not None else None
        np.format_float_scientific(x, precision=p)
    else:
        raise

Prevention

When it happens

Trigger: Calling np.format_float_scientific / np.format_float_positional (or anything routed through them, such as np.array2string with formatter options) with a strictly negative value for precision, pad_left, pad_right, exp_digits, or min_digits. For example np.format_float_scientific(1.0, precision=-2) or np.format_float_positional(0.5, pad_left=-1).

Common situations: Off-by-one math on a computed width/precision before passing it to a formatter; passing a value that another API returns as -1 on 'unset' without re-checking; confusing the linewidth=-1 sentinel of np.set_printoptions (which means 'no wrapping') with the precision-family arguments, which do NOT accept -1.

Related errors


AI-assisted analysis of numpy/numpy@44f1f77dd8 (2026-08-11). Data as JSON: /api/errors/9ded4b07ea6e339b. Report an issue: GitHub.

Appendix: source

Thrown at numpy/_core/arrayprint.py:982

        s = '[' + s[len(hanging_indent):] + ']'
        return s

    try:
        # invoke the recursive part with an initial index and prefix
        return recurser(index=(),
                        hanging_indent=next_line_prefix,
                        curr_width=line_width)
    finally:
        # recursive closures have a cyclic reference to themselves, which
        # requires gc to collect (gh-10620). To avoid this problem, for
        # performance, we break the cycle:
        recurser = None

def _none_or_positive_arg(x, name):
    if x is None:
        return -1
    if x < 0:
        raise ValueError(f"{name} must be >= 0")
    return x

class FloatingFormat:
    """ Formatter for subtypes of np.floating """
    def __init__(self, data, precision, floatmode, suppress_small, sign=False,
                 *, legacy=None):
        # for backcompatibility, accept bools
        if isinstance(sign, bool):
            sign = '+' if sign else '-'

        self._legacy = legacy
        if self._legacy <= 113:
            # when not 0d, legacy does not support '-'
            if data.shape != () and sign == '-':
                sign = ' '

        self.floatmode = floatmode
        if floatmode == 'unique':

View on GitHub (pinned to 44f1f77dd8)