microsoft/qlib · error · NotImplementedError

Please implement the `list_recorders` method.

Error message

Please implement the `list_recorders` method.

What it means

Experiment.list_recorders(rtype, **flt_kwargs) is an abstract method that must return either a dict (id -> Recorder) or a list of Recorder objects, optionally filtered (e.g. status=Recorder.STATUS_FI). The base stub raises NotImplementedError; MLflowExperiment implements it by listing runs via MlflowClient with a 50000-record cap.

Source

Thrown at qlib/workflow/exp.py:240

        self, rtype: Literal["dict", "list"] = RT_D, **flt_kwargs
    ) -> Union[List[Recorder], Dict[str, Recorder]]:
        """
        List all the existing recorders of this experiment. Please first get the experiment instance before calling this method.
        If user want to use the method `R.list_recorders()`, please refer to the related API document in `QlibRecorder`.

        flt_kwargs : dict
            filter recorders by conditions
            e.g.  list_recorders(status=Recorder.STATUS_FI)

        Returns
        -------
        The return type depends on `rtype`
            if `rtype` == "dict":
                A dictionary (id -> recorder) of recorder information that being stored.
            elif `rtype` == "list":
                A list of Recorder.
        """
        raise NotImplementedError(f"Please implement the `list_recorders` method.")


class MLflowExperiment(Experiment):
    """
    Use mlflow to implement Experiment.
    """

    def __init__(self, id, name, uri):
        super(MLflowExperiment, self).__init__(id, name)
        self._uri = uri
        self._default_rec_name = "mlflow_recorder"
        self._client = mlflow.tracking.MlflowClient(tracking_uri=self._uri)

    def __repr__(self):
        return "{name}(id={id}, info={info})".format(name=self.__class__.__name__, id=self.id, info=self.info)

    def start(self, *, recorder_id=None, recorder_name=None, resume=False):
        logger.info(f"Experiment {self.id} starts running ...")

View on GitHub (pinned to 79633dd950)

Solutions

  1. Get the experiment from R.get_exp(...) so the MLflow implementation is used.
  2. Implement list_recorders in your subclass honoring rtype ('dict'/'list') and status filters.
  3. For large result sets, remember the MLflow implementation caps at UNLIMITED=50000 runs.

Example fix

# before
Experiment('1', 'e').list_recorders()  # NotImplementedError

# after
exp = R.get_exp(experiment_name='alpha158')
recs = exp.list_recorders(status=Recorder.STATUS_FI)  # dict of finished recorders
Defensive patterns

Strategy: type-guard

Validate before calling

from qlib.workflow.exp import Experiment
assert exp.__class__.list_recorders is not Experiment.list_recorders, 'listing unsupported'

Type guard

def listable(exp) -> bool:
    from qlib.workflow.exp import Experiment
    return exp.__class__.list_recorders is not Experiment.list_recorders

Prevention

When it happens

Trigger: exp.list_recorders() on a directly instantiated Experiment; R.list_recorders(exp_name) delegating to a custom Experiment subclass that never overrode list_recorders.

Common situations: Custom backends implementing only run creation; analysis notebooks enumerating finished recorders; migrations where the subclass was written against an older interface.

Related errors


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