microsoft/qlib · error · AttributeError

The operator [ ] 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.

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.

Appendix: 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)