{"record":{"id":"db486eb2d7997c57","repo":"microsoft/qlib","slug":"unknown-metric-s-db486e","errorCode":null,"errorMessage":"unknown metric `%s`","messagePattern":"unknown metric `(.+?)`","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"qlib/contrib/model/pytorch_alstm_ts.py","lineNumber":168,"sourceCode":"        if weight is None:\n            weight = torch.ones_like(label)\n\n        if self.loss == \"mse\":\n            return self.mse(pred[mask], label[mask], weight[mask])\n\n        raise ValueError(\"unknown loss `%s`\" % self.loss)\n\n    def metric_fn(self, pred, label):\n        mask = torch.isfinite(label)\n\n        if self.metric in (\"\", \"loss\"):\n            return -self.loss_fn(pred[mask], label[mask])\n        elif self.metric == \"mse\":\n            mask = ~torch.isnan(label)\n            weight = torch.ones_like(label)\n            return -self.mse(pred[mask], label[mask], weight[mask])\n\n        raise ValueError(\"unknown metric `%s`\" % self.metric)\n\n    def train_epoch(self, data_loader):\n        self.ALSTM_model.train()\n\n        for data, weight in data_loader:\n            feature = data[:, :, 0:-1].to(self.device)\n            label = data[:, -1, -1].to(self.device)\n\n            pred = self.ALSTM_model(feature.float())\n            loss = self.loss_fn(pred, label, weight.to(self.device))\n\n            self.train_optimizer.zero_grad()\n            loss.backward()\n            torch.nn.utils.clip_grad_value_(self.ALSTM_model.parameters(), 3.0)\n            self.train_optimizer.step()\n\n    def test_epoch(self, data_loader):\n        self.ALSTM_model.eval()","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/contrib/model/pytorch_alstm_ts.py#L150-L186","documentation":"ALSTMTSModel.metric_fn only knows two metric modes: the empty string or 'loss' (negated training loss) and 'mse'. Any other value stored in self.metric makes the method fall through every branch and raise ValueError at the end of metric_fn in qlib/contrib/model/pytorch_alstm_ts.py. This metric is computed every epoch on the validation set to drive early stopping, so a bad value aborts training inside fit().","triggerScenarios":"Constructing ALSTMTSModel(metric='ic') or any string other than ''/'loss'/'mse', then calling fit(); the first validation epoch calls metric_fn(pred, label) which raises. Also triggered by typo'd YAML/JSON workflow configs that feed the metric hyperparameter verbatim.","commonSituations":"Copying a workflow config written for a different qlib model (e.g. LGBModel where metric='ic' is legal) and reusing it for ALSTM; upgrading qlib versions where supported metric names changed; assuming ranking metrics like IC are supported because they appear elsewhere in qlib.","solutions":["Set metric to 'mse' or leave it as the default '' (both mean loss-based scoring) in the ALSTMTSModel constructor or workflow config.","Check your workflow YAML/JSON 'metric' hyperparameter for typos or values copied from another model class.","If you need a custom metric, subclass ALSTMTSModel and extend metric_fn with a new elif branch before the final raise."],"exampleFix":"# before\nmodel = ALSTMTSModel(metric='ic')\n\n# after\nmodel = ALSTMTSModel(metric='mse')","handlingStrategy":"validation","validationCode":"from qlib.contrib.model.pytorch_alstm_ts import ALSTMTSModel\nallowed = {'', 'loss', 'mse'}\nassert model.metric in allowed, f\"metric must be one of {allowed}, got {model.metric!r}\"","typeGuard":"def is_valid_alstm_metric(metric: str) -> bool:\n    return metric in ('', 'loss', 'mse')","tryCatchPattern":"try:\n    model.fit(dataset)\nexcept ValueError as e:\n    if 'unknown metric' in str(e):\n        raise ValueError(f\"bad ALSTM metric {model.metric!r}; use '', 'loss' or 'mse'\") from e\n    raise","preventionTips":["Validate hyperparameters against the target model's allowed values before starting long training runs.","Do not copy metric settings between different qlib contrib models; each has its own vocabulary.","Encode model hyperparameter schemas in your config tooling so invalid values fail at config-load time."],"tags":["pytorch","qlib","config-validation","metrics","alstm"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}