microsoft/qlib · critical · OSError
nfs-common is not found, please install it by execute: sudo
Error message
nfs-common is not found, please install it by execute: sudo apt install nfs-common
What it means
Base ExpressionCache._uri (qlib/data/cache.py:353) is the abstract hook that maps (instrument, field, start_time, end_time, freq) to a cache-file URI for expression data. The base class has no mechanism of its own, so it raises NotImplementedError telling you to override it to match your cache mechanism. The public expression() method catches NotImplementedError from _expression and falls back to the wrapped provider, but _uri has no such fallback.
Source
Thrown at qlib/__init__.py:172
if _is_mount:
break
_remote_uri = "/".join(_remote_uri.split("/")[:-1])
_mount_path = "/".join(_mount_path.split("/")[:-1])
_check_level_num -= 1
if not _is_mount:
try:
Path(mount_path).mkdir(parents=True, exist_ok=True)
except Exception as e:
raise OSError(
f"Failed to create directory {mount_path}, please create {mount_path} manually!"
) from e
# check nfs-common
command_res = os.popen("dpkg -l | grep nfs-common")
command_res = command_res.readlines()
if not command_res:
raise OSError("nfs-common is not found, please install it by execute: sudo apt install nfs-common")
# manually mount
try:
subprocess.run(mount_command, check=True, capture_output=True, text=True)
LOG.info("Mount finished.")
except subprocess.CalledProcessError as e:
if e.returncode == 256:
raise OSError("Mount failed: requires sudo or permission denied") from e
elif e.returncode == 32512:
raise OSError(f"mount {provider_uri} on {mount_path} error! Command error") from e
else:
raise OSError(f"Mount failed: {e.stderr}") from e
else:
LOG.warning(f"{_remote_uri} on {_mount_path} is already mounted")
def init_from_yaml_conf(conf_path, **kwargs):
"""init_from_yaml_conf
View on GitHub (pinned to 79633dd950)
Solutions
- If you just want disk caching, configure qlib.init(expression_cache=DiskExpressionCache) instead of a custom class
- In your subclass, override _uri to return the cache path/URI string for the given (instrument, field, start_time, end_time, freq)
- Follow the DiskExpressionCache implementation (cache.py) as the reference pattern
Example fix
# before
class MyExprCache(ExpressionCache):
def _expression(self, instrument, field, start_time, end_time, freq):
...
# after
class MyExprCache(ExpressionCache):
def _uri(self, instrument, field, start_time, end_time, freq):
return str(self.cache_uri / f"{instrument}/{field}.bin") # your mechanism Defensive patterns
Strategy: type-guard
Validate before calling
from qlib.data.cache import ExpressionCache
assert MyExprCache._uri is not ExpressionCache._uri, \
"custom ExpressionCache must override _uri" Type guard
def is_usable_expr_cache(cls) -> bool:
return all(
getattr(cls, m) is not getattr(ExpressionCache, m)
for m in ("_uri", "_expression", "update")
) Prevention
- Prefer qlib's DiskExpressionCache; custom backends need _uri, _expression, update all overridden
- Add an init-time assertion for overridden cache methods
- Write one smoke test that hits uri() before running full pipelines
When it happens
Trigger: Instantiating a subclass of ExpressionCache that overrides _expression but not _uri (or using the base ExpressionCache directly) and calling a code path that needs the cache file location — e.g. uri(), update(), or client-side cache walking.
Common situations: Writing a custom expression cache (e.g. backed by S3, a DB) and missing one of the required overrides; note qlib ships DiskExpressionCache as the concrete implementation — use it unless you truly need a custom backend.
Related errors
- Mount failed: requires sudo or permission denied
- mount {provider_uri} on {mount_path} error! Command error
- Mount failed: {e.stderr}
- We can't find the project path
- account must be in (int, float, dict)
AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15).
Data as JSON: /api/errors/1dad936760767995.
Report an issue: GitHub.