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
- Check the operator name spelling and capitalization against qlib.data.ops (e.g. Ref, Mean, Std, Rank, Corr).
- If it is a custom operator, call Operators.register_custom_ops([MyOp]) before parsing/evaluating expressions in this process.
- Upgrade or align qlib to the version whose operator set includes the name you are using.
- 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
- Register all custom operators once at process start, before any qlib.init data access.
- Keep feature-name lists in one module and lint them against Operators._ops in CI.
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
- {str(e)}. \n\t{warning_info}
- The rolling window size of Skewness operation should >= 3
- The rolling window size of Kurtosis operation should >= 5
- operator must be subclass of ExpressionOps, not {}
- PIT database does not support referring to future period (e.
AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15).
Data as JSON: /api/errors/e1ec9841e2825f9b.
Report an issue: GitHub.