microsoft/qlib · error · AttributeError

The operator [{0}] is not registered

Error message

The operator [{0}] is not registered

What it means

Raised by OpsWrapper.__getattr__ (qlib/data/ops.py) when an expression string references an operator name that is not in the Operators registry. Qlib parses expression strings like "Ref($close, 5)" by looking up each capitalized token as an attribute of Operators; unknown names produce this AttributeError with the exact operator name in brackets.

Source

Thrown at qlib/data/ops.py:1663

        """
        for _operator in ops_list:
            if isinstance(_operator, dict):
                _ops_class, _ = get_callable_kwargs(_operator)
            else:
                _ops_class = _operator

            if not issubclass(_ops_class, (Expression,)):
                raise TypeError("operator must be subclass of ExpressionOps, not {}".format(_ops_class))

            if _ops_class.__name__ in self._ops:
                get_module_logger(self.__class__.__name__).warning(
                    "The custom operator [{}] will override the qlib default definition".format(_ops_class.__name__)
                )
            self._ops[_ops_class.__name__] = _ops_class

    def __getattr__(self, key):
        if key not in self._ops:
            raise AttributeError("The operator [{0}] is not registered".format(key))
        return self._ops[key]


Operators = OpsWrapper()


def register_all_ops(C):
    """register all operator"""
    logger = get_module_logger("ops")

    from qlib.data.pit import P, PRef  # pylint: disable=C0415

    Operators.reset()
    Operators.register(OpsList + [P, PRef])

    if getattr(C, "custom_ops", None) is not None:
        Operators.register(C.custom_ops)
        logger.debug("register custom operator {}".format(C.custom_ops))

View on GitHub (pinned to 79633dd950)

Solutions

  1. Check the operator name spelling and capitalization against qlib.data.ops (e.g. Ref, Mean, Std, Rank, Corr).
  2. If it is a custom operator, call Operators.register_custom_ops([MyOp]) before parsing/evaluating expressions in this process.
  3. Upgrade or align qlib to the version whose operator set includes the name you are using.
  4. Print sorted(Operators._ops.keys()) to see every currently registered operator name.

Example fix

# before
fields = ["Reff($close, 5)"]  # typo: unknown operator

# after
fields = ["Ref($close, 5)"]
Defensive patterns

Strategy: validation

Validate before calling

known = set(Operators._ops.keys())
tokens = extract_operator_names(expr)  # your parser: leading capitalized tokens
unknown = tokens - known
if unknown:
    raise NameError(f"unregistered operators: {sorted(unknown)}")

Type guard

def all_operators_registered(expr: str) -> bool:
    return extract_operator_names(expr) <= set(Operators._ops.keys())

Try / catch

try:
    D.features(insts, [expr], start, end)
except AttributeError as e:
    if "is not registered" in str(e):
        # surface actionable message with registered op list
        raise RuntimeError(f"{e}; registered ops: {sorted(Operators._ops)}") from e
    raise

Prevention

When it happens

Trigger: Evaluating an expression containing a typo or unregistered operator, e.g. "Reff($close, 5)" (extra f), "EMA($close, 5)" if not registered, or a custom operator used before calling Operators.register_custom_ops.

Common situations: Typos in hand-written feature strings; using a custom operator in a config before registering it in the same process; operators available only in newer qlib versions (version drift between docs and installed package); case errors (e.g. "mean" instead of "Mean").

Related errors


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