{"record":{"id":"1dad936760767995","repo":"microsoft/qlib","slug":"nfs-common-is-not-found-please-install-it-by-exec","errorCode":null,"errorMessage":"nfs-common is not found, please install it by execute: sudo apt install nfs-common","messagePattern":"nfs-common is not found, please install it by execute: sudo apt install nfs-common","errorType":"exception","errorClass":"OSError","httpStatus":null,"severity":"critical","filePath":"qlib/__init__.py","lineNumber":172,"sourceCode":"                if _is_mount:\n                    break\n                _remote_uri = \"/\".join(_remote_uri.split(\"/\")[:-1])\n                _mount_path = \"/\".join(_mount_path.split(\"/\")[:-1])\n                _check_level_num -= 1\n\n            if not _is_mount:\n                try:\n                    Path(mount_path).mkdir(parents=True, exist_ok=True)\n                except Exception as e:\n                    raise OSError(\n                        f\"Failed to create directory {mount_path}, please create {mount_path} manually!\"\n                    ) from e\n\n                # check nfs-common\n                command_res = os.popen(\"dpkg -l | grep nfs-common\")\n                command_res = command_res.readlines()\n                if not command_res:\n                    raise OSError(\"nfs-common is not found, please install it by execute: sudo apt install nfs-common\")\n                # manually mount\n                try:\n                    subprocess.run(mount_command, check=True, capture_output=True, text=True)\n                    LOG.info(\"Mount finished.\")\n                except subprocess.CalledProcessError as e:\n                    if e.returncode == 256:\n                        raise OSError(\"Mount failed: requires sudo or permission denied\") from e\n                    elif e.returncode == 32512:\n                        raise OSError(f\"mount {provider_uri} on {mount_path} error! Command error\") from e\n                    else:\n                        raise OSError(f\"Mount failed: {e.stderr}\") from e\n            else:\n                LOG.warning(f\"{_remote_uri} on {_mount_path} is already mounted\")\n\n\ndef init_from_yaml_conf(conf_path, **kwargs):\n    \"\"\"init_from_yaml_conf\n","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/__init__.py#L154-L190","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nclass MyExprCache(ExpressionCache):\n    def _expression(self, instrument, field, start_time, end_time, freq):\n        ...\n\n# after\nclass MyExprCache(ExpressionCache):\n    def _uri(self, instrument, field, start_time, end_time, freq):\n        return str(self.cache_uri / f\"{instrument}/{field}.bin\")  # your mechanism","handlingStrategy":"type-guard","validationCode":"from qlib.data.cache import ExpressionCache\n\nassert MyExprCache._uri is not ExpressionCache._uri, \\\n    \"custom ExpressionCache must override _uri\"","typeGuard":"def is_usable_expr_cache(cls) -> bool:\n    return all(\n        getattr(cls, m) is not getattr(ExpressionCache, m)\n        for m in (\"_uri\", \"_expression\", \"update\")\n    )","tryCatchPattern":null,"preventionTips":["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"],"tags":["qlib","cache","custom-backend","not-implemented"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}