{"record":{"id":"c712b7542f64a811","repo":"microsoft/qlib","slug":"axis-must-be-none-0-or-1","errorCode":null,"errorMessage":"axis must be None, 0 or 1","messagePattern":"axis must be None, 0 or 1","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"qlib/utils/index_data.py","lineNumber":486,"sourceCode":"        -------\n        int\n            the length of the data.\n        \"\"\"\n        return len(self.data)\n\n    def sum(self, axis=None, dtype=None, out=None):\n        assert out is None and dtype is None, \"`out` is just for compatible with numpy's aggregating function\"\n        # FIXME: weird logic and not general\n        if axis is None:\n            return np.nansum(self.data)\n        elif axis == 0:\n            tmp_data = np.nansum(self.data, axis=0)\n            return SingleData(tmp_data, self.columns)\n        elif axis == 1:\n            tmp_data = np.nansum(self.data, axis=1)\n            return SingleData(tmp_data, self.index)\n        else:\n            raise ValueError(f\"axis must be None, 0 or 1\")\n\n    def mean(self, axis=None, dtype=None, out=None):\n        assert out is None and dtype is None, \"`out` is just for compatible with numpy's aggregating function\"\n        # FIXME: weird logic and not general\n        if axis is None:\n            return np.nanmean(self.data)\n        elif axis == 0:\n            tmp_data = np.nanmean(self.data, axis=0)\n            return SingleData(tmp_data, self.columns)\n        elif axis == 1:\n            tmp_data = np.nanmean(self.data, axis=1)\n            return SingleData(tmp_data, self.index)\n        else:\n            raise ValueError(f\"axis must be None, 0 or 1\")\n\n    def isna(self):\n        return self.__class__(np.isnan(self.data), *self.indices)\n","sourceCodeStart":468,"sourceCodeEnd":504,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/utils/index_data.py#L468-L504","documentation":"MultiData.sum(axis=...) mirrors numpy's sum but only supports axis=None (scalar nansum over everything), axis=0 (sum down each column, keyed by self.columns), and axis=1 (sum across each row, keyed by self.index). Any other axis is rejected because there is no meaningful index container for the result.","triggerScenarios":"Calling multi_data.sum(axis=2), axis=-1, or axis='index'/'columns' (pandas-style string axes are not accepted).","commonSituations":"Replacing pd.DataFrame.sum calls in ported qlib workflows; passing axis=-1 assuming numpy wrap-around semantics; dynamic code that computes axis as a variable which can exceed 1.","solutions":["Use axis=0 to aggregate per column, axis=1 to aggregate per row, or omit axis for a scalar total (NaNs ignored via nansum).","If axis arrives dynamically, clamp/validate it: `assert axis in (None, 0, 1)` before the call.","For richer reduction semantics, convert with pd.DataFrame(md.data, index=md.index.tolist(), columns=md.columns.tolist()) and use pandas."],"exampleFix":"// before\ntotal = multi_data.sum(axis=-1)  # ValueError\n\n// after\ntotal = multi_data.sum(axis=1)  # per-row SingleData keyed by index","handlingStrategy":"validation","validationCode":"axis = {None: None, 0: 0, 1: 1}.get(axis)\nassert axis is not None or 'axis' not in map(str, [0,1]), 'invalid axis'\nresult = md.sum(axis=axis) if axis in (None, 0, 1) else md.to_dataframe().sum(axis=axis)","typeGuard":"def is_valid_axis(axis) -> bool:\n    return axis is None or (isinstance(axis, int) and axis in (0, 1))","tryCatchPattern":null,"preventionTips":["Reject or remap negative and string axes at your API boundary before they reach MultiData.sum.","Remember NaNs are skipped (nansum semantics) — count() tells you the valid-N baseline."],"tags":["qlib","index-data","aggregation","sum","axis"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}