{"record":{"id":"5cbc10e4a356fae1","repo":"microsoft/qlib","slug":"config-path-is-invalid","errorCode":null,"errorMessage":"Config path is invalid.","messagePattern":"Config path is invalid\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"qlib/contrib/tuner/config.py","lineNumber":15,"sourceCode":"# Copyright (c) Microsoft Corporation.\n# Licensed under the MIT License.\n\n# pylint: skip-file\n# flake8: noqa\n\nimport copy\nimport os\nfrom ruamel.yaml import YAML\n\n\nclass TunerConfigManager:\n    def __init__(self, config_path):\n        if not config_path:\n            raise ValueError(\"Config path is invalid.\")\n        self.config_path = config_path\n\n        with open(config_path) as fp:\n            yaml = YAML(typ=\"safe\", pure=True)\n            config = yaml.load(fp)\n        self.config = copy.deepcopy(config)\n\n        self.pipeline_ex_config = PipelineExperimentConfig(config.get(\"experiment\", dict()), self)\n        self.pipeline_config = config.get(\"tuner_pipeline\", list())\n        self.optim_config = OptimizationConfig(config.get(\"optimization_criteria\", dict()), self)\n\n        self.time_config = config.get(\"time_period\", dict())\n        self.data_config = config.get(\"data\", dict())\n        self.backtest_config = config.get(\"backtest\", dict())\n        self.qlib_client_config = config.get(\"qlib_client\", dict())\n\n\nclass PipelineExperimentConfig:","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/contrib/tuner/config.py#L1-L33","documentation":"TunerConfigManager (qlib/contrib/tuner/config.py) validates its input at construction: a falsy config_path (empty string, None) raises ValueError('Config path is invalid.'). The tuner cannot proceed without a YAML file describing experiment, tuner_pipeline and optimization criteria, so it fails immediately rather than erroring later on a missing file handle.","triggerScenarios":"Calling TunerConfigManager(None) or TunerConfigManager(''), typically because a CLI argument or config variable was never set; note a non-empty but nonexistent path instead fails with FileNotFoundError at open().","commonSituations":"Running the hyperparameter tuning workflow where the config path argument is optional and the user omitted it; environment/config plumbing returning None (e.g. os.environ.get('TUNER_CONF') with the variable unset).","solutions":["Pass a real path to a valid tuner YAML config: TunerConfigManager('tuner_config.yaml')","If the path comes from an env var or CLI, check it is set and non-empty before constructing","Note the check only catches empty/None paths; a wrong-but-nonempty path raises FileNotFoundError next, so verify the file exists too"],"exampleFix":"# before\npath = os.environ.get('TUNER_CONF')\ncm = TunerConfigManager(path)\n\n# after\npath = os.environ.get('TUNER_CONF')\nassert path and os.path.isfile(path), 'set TUNER_CONF to a tuner yaml file'\ncm = TunerConfigManager(path)","handlingStrategy":"validation","validationCode":"import os\n\nconfig_path = os.environ.get('TUNER_CONF')\nif not config_path or not os.path.isfile(config_path):\n    raise FileNotFoundError('provide a valid tuner config path')\ncm = TunerConfigManager(config_path)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Require and check the config path argument in CLI wrappers before constructing TunerConfigManager","Validate both non-emptiness and file existence in one guard (the class only checks emptiness)"],"tags":["qlib","tuner","configuration","validation"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}