microsoft/qlib · error · RuntimeError

This recorder is not saved in the local file system.

Error message

This recorder is not saved in the local file system.

What it means

MLflowRecorder.local_dir derives the recorder's on-disk directory from artifact_uri (stripping the file: prefix and taking the parent path). If that resolved path is not an existing local directory (os.path.isdir fails), it raises RuntimeError — the artifacts live somewhere that is not this machine's filesystem. A separate ValueError is raised when artifact_uri is None (run never started properly); this RuntimeError specifically means 'the URI resolved, but not to a local dir we can see'.

Source

Thrown at qlib/workflow/recorder.py:328

    @property
    def artifact_uri(self):
        return self._artifact_uri

    def get_local_dir(self):
        """
        This function will return the directory path of this recorder.
        """
        if self.artifact_uri is not None:
            if platform.system() == "Windows":
                local_dir_path = Path(self.artifact_uri.lstrip("file:").lstrip("/")).parent
            else:
                local_dir_path = Path(self.artifact_uri.lstrip("file:")).parent
            local_dir_path = str(local_dir_path.resolve())
            if os.path.isdir(local_dir_path):
                return local_dir_path
            else:
                raise RuntimeError("This recorder is not saved in the local file system.")

        else:
            raise ValueError(
                "Please make sure the recorder has been created and started properly before getting artifact uri."
            )

    def start_run(self):
        # set the tracking uri
        mlflow.set_tracking_uri(self.uri)
        # start the run
        run = mlflow.start_run(self.id, self.experiment_id, self.name)
        # save the run id and artifact_uri
        self.id = run.info.run_id
        self._artifact_uri = run.info.artifact_uri
        self.start_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.status = Recorder.STATUS_R
        logger.info(f"Recorder {self.id} starts running under Experiment {self.experiment_id} ...")

View on GitHub (pinned to 79633dd950)

Solutions

  1. Ensure artifacts are local: set the artifact root to a local/shared path when creating the experiment (mlflow.create_experiment(..., artifact_location='file:///mnt/shared/mlruns')) and mount it on the client machine
  2. If you only need artifact contents, avoid local_dir and use recorder.load_object(name) / list_artifacts, which go through the MLflow artifact repo and work with remote stores
  3. Verify the path exists: print recorder.artifact_uri, resolve it locally (strip file:), and check the mount; re-mount or fix permissions
  4. Re-create or restore the mlruns artifact directory if it was deleted

Example fix

# before
# MLflow server with server-side artifacts
rec.local_dir()  # RuntimeError: not saved in local file system

# after (option 1: local artifact root)
mlflow.create_experiment('my_exp', artifact_location='file:///mnt/shared/mlruns/my_exp')
# after (option 2: use artifact API instead of local path)
pred = rec.load_object('pred.pkl')
Defensive patterns

Strategy: validation

Validate before calling

import os
from pathlib import Path

def local_dir_safe(recorder) -> str:
    uri = recorder.artifact_uri
    if uri is None:
        raise ValueError('recorder not started; no artifact_uri')
    if not uri.startswith('file:'):
        raise RuntimeError(f'artifacts are remote ({uri}); local_dir() unsupported')
    p = str(Path(uri[len('file:'):]).parent.resolve())
    if not os.path.isdir(p):
        raise RuntimeError(f'artifact path {p} missing; check mounts')
    return p

Type guard

import os
from pathlib import Path

def has_local_artifacts(recorder) -> bool:
    uri = getattr(recorder, 'artifact_uri', None)
    if not uri or not uri.startswith('file:'):
        return False
    return os.path.isdir(str(Path(uri[len('file:'):]).parent.resolve()))

Try / catch

try:
    path = rec.local_dir()
except RuntimeError:
    path = None  # remote artifact store: fall back to load_object()/list_artifacts()
except ValueError:
    raise  # run never started properly; caller must start the recorder first

Prevention

When it happens

Trigger: MLflow tracking server with a remote artifact store (s3://, nfs, gs://, or a file path on another host) — artifact_uri then does not map to a local directory; artifacts root moved or deleted after the run; artifact_uri uses a file: path that was mounted elsewhere; reading a shared mlruns directory that is not mounted on this machine.

Common situations: Pointing MLFLOW_TRACKING_URI at a central server while artifacts default to the server-side ./mlruns; switching machines and losing the mount that previously held the artifacts; cleanup scripts deleting mlruns directories; artifact_location configured per-experiment to a remote scheme.

Related errors


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