microsoft/qlib · error · ValueError

Cut operator l shoud > 0 and r should < 0

Error message

Cut operator l shoud > 0 and r should < 0

What it means

Raised by qlib's Cut operator (qlib/contrib/ops/high_freq.py) when the constructor receives invalid cut bounds. Cut deletes the first `left` and last `-right` elements of a feature series, so `left` must be a strictly positive integer (or None) and `right` a strictly negative integer (or None). Any other sign or zero value fails fast in __init__ before any data is loaded.

Source

Thrown at qlib/contrib/ops/high_freq.py:263

    ----------
    feature : Expression
        feature instance
    l : int
        l > 0, delete the first l elements of feature (default is None, which means 0)
    r : int
        r < 0, delete the last -r elements of feature (default is None, which means 0)
    Returns
    ----------
    feature:
        A series with the first l and last -r elements deleted from the feature.
        Note: It is deleted from the raw data, not the sliced data
    """

    def __init__(self, feature, left=None, right=None):
        self.left = left
        self.right = right
        if (self.left is not None and self.left <= 0) or (self.right is not None and self.right >= 0):
            raise ValueError("Cut operator l shoud > 0 and r should < 0")

        super(Cut, self).__init__(feature)

    def _load_internal(self, instrument, start_index, end_index, freq):
        series = self.feature.load(instrument, start_index, end_index, freq)
        return series.iloc[self.left : self.right]

    def get_extended_window_size(self):
        ll = 0 if self.left is None else self.left
        rr = 0 if self.right is None else abs(self.right)
        lft_etd, rght_etd = self.feature.get_extended_window_size()
        lft_etd = lft_etd + ll
        rght_etd = rght_etd + rr
        return lft_etd, rght_etd

View on GitHub (pinned to 79633dd950)

Solutions

  1. Pass left as a positive int > 0 (number of head elements to drop) or leave it as None
  2. Pass right as a negative int < 0 (iloc-style end, e.g. -5 drops the last 5 rows) or leave it as None
  3. If you intended no cut on one side, explicitly use None instead of 0
  4. Double-check the docstring: the operator wraps series.iloc[left:right], so use iloc semantics

Example fix

# before
Cut(feature, left=0, right=5)

# after
Cut(feature, left=None, right=-5)  # drop last 5 elements only
Defensive patterns

Strategy: validation

Validate before calling

def valid_cut_params(left, right):
    return (left is None or (isinstance(left, int) and left > 0)) and \
           (right is None or (isinstance(right, int) and right < 0))

assert valid_cut_params(left, right), 'left must be >0 or None; right must be <0 or None'

Type guard

def is_valid_cut(left, right) -> bool:
    return (left is None or left > 0) and (right is None or right < 0)

Prevention

When it happens

Trigger: Calling Cut(feature, left=0, right=-5), Cut(feature, left=2, right=0), Cut(feature, left=-1, ...), or Cut(feature, ..., right=3). The check `self.left <= 0` (when left is not None) or `self.right >= 0` (when right is not None) fires immediately at construction time.

Common situations: Developers porting pandas iloc slicing habits (where 0 is a valid bound) into Cut's semantic where the counts are one-based and sign-encoded; passing right as a positive count of tail elements instead of a negative iloc-style bound; using Cut in high-frequency expression strings with wrong literals.

Related errors


AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15). Data as JSON: /api/errors/0b82835b28030b85. Report an issue: GitHub.