microsoft/qlib · error · ValueError

No valid recorder has been found, please make sure the input

Error message

No valid recorder has been found, please make sure the input recorder id is correct.

What it means

Raised by MLflowExperiment._get_recorder when MlflowClient.get_run(recorder_id) throws MlflowException (run not found, deleted, or malformed id); the MLflow error is chained into this ValueError. It means the id simply does not correspond to a run inside this experiment's tracking store.

Source

Thrown at qlib/workflow/exp.py:304

    def _get_recorder(self, recorder_id=None, recorder_name=None):
        """
        Method for getting or creating a recorder. It will try to first get a valid recorder, if exception occurs, it will
        raise errors.

        Quoting docs of search_runs from MLflow
        > The default ordering is to sort by start_time DESC, then run_id.
        """
        assert (
            recorder_id is not None or recorder_name is not None
        ), "Please input at least one of recorder id or name before retrieving recorder."
        if recorder_id is not None:
            try:
                run = self._client.get_run(recorder_id)
                recorder = MLflowRecorder(self.id, self._uri, mlflow_run=run)
                return recorder
            except MlflowException as mlflow_exp:
                raise ValueError(
                    "No valid recorder has been found, please make sure the input recorder id is correct."
                ) from mlflow_exp
        elif recorder_name is not None:
            logger.warning(
                f"Please make sure the recorder name {recorder_name} is unique, we will only return the latest recorder if there exist several matched the given name."
            )
            recorders = self.list_recorders()
            for rid in recorders:
                if recorders[rid].name == recorder_name:
                    return recorders[rid]
            raise ValueError("No valid recorder has been found, please make sure the input recorder name is correct.")

    def search_records(self, **kwargs):
        filter_string = "" if kwargs.get("filter_string") is None else kwargs.get("filter_string")
        run_view_type = 1 if kwargs.get("run_view_type") is None else kwargs.get("run_view_type")
        max_results = 100000 if kwargs.get("max_results") is None else kwargs.get("max_results")
        order_by = kwargs.get("order_by")

View on GitHub (pinned to 79633dd950)

Solutions

  1. Verify the recorder exists first: exp.list_recorders() and confirm the id-keyed dict contains it.
  2. Make sure the tracking URI matches where the run was created (check R.get_uri() / C.exp_manager['kwargs']['uri']).
  3. Strip/normalize the id and confirm it is a 32-hex MLflow run_id, not an experiment_id or recorder name.
  4. If the run was deleted, restore it in MLflow or accept it is gone.

Example fix

# before
rec = exp.get_recorder(recorder_id='abc123')  # ValueError: no valid recorder

# after
rids = exp.list_recorders()  # dict keyed by run_id
rec = exp.get_recorder(recorder_id=next(iter(rids)))  # use a verified id
Defensive patterns

Strategy: validation

Validate before calling

rids = exp.list_recorders()  # dict keyed by run_id
if recorder_id not in rids:
    raise KeyError(f'{recorder_id} not in experiment {exp.id}; available: {list(rids)[:5]}')
rec = exp.get_recorder(recorder_id=recorder_id)

Type guard

def recorder_id_exists(exp, rid: str) -> bool:
    return rid in exp.list_recorders()

Try / catch

try:
    rec = exp.get_recorder(recorder_id=rid)
except ValueError as e:
    if 'recorder id is correct' in str(e):
        rid = next(iter(exp.list_recorders()))  # recover with a known id
        rec = exp.get_recorder(recorder_id=rid)
    else:
        raise

Prevention

When it happens

Trigger: exp.get_recorder(recorder_id='<bad-or-deleted-run-id>'); recorder_id copied from a different tracking URI / mlruns directory; run was soft-deleted via delete_run before retrieval; id has trailing whitespace or wrong case.

Common situations: Switching exp_manager uri between runs (file:./mlruns vs file:./another_mlruns) so ids from the old store are looked up in the new one; resuming old experiments whose artifacts were cleaned; typos when pasting run ids into R.get_recorder.

Related errors


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