{"record":{"id":"610d297ead4b0042","repo":"ZhuLinsen/daily_stock_analysis","slug":"excel-e-1-xlsx-2-3","errorCode":null,"errorMessage":"Excel 解析失败: {e}。请确认：(1) 文件为 .xlsx 格式；(2) 工作表不为空；(3) 文件未损坏。若为 .xls 格式，请另存为 .xlsx 后重试。","messagePattern":"Excel 解析失败: (.+?)。请确认：\\(1\\) 文件为 \\.xlsx 格式；\\(2\\) 工作表不为空；\\(3\\) 文件未损坏。若为 \\.xls 格式，请另存为 \\.xlsx 后重试。","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/services/import_parser.py","lineNumber":173,"sourceCode":"            # Use header=None to avoid silently consuming the first data row as column names\n            # when the sheet has no header row. We detect headers the same way as the CSV path.\n            df = pd.read_excel(io.BytesIO(data), sheet_name=0, engine=\"openpyxl\", header=None, dtype=str)\n            if df is None or df.empty:\n                return []\n            df = df.fillna(\"\")\n            first_row = [str(x).strip().lower() for x in df.iloc[0].tolist()]\n            if any(c in _CODE_ALIASES or c in _NAME_ALIASES for c in first_row):\n                df.columns = df.iloc[0]\n                df = df.iloc[1:].reset_index(drop=True)\n            return _parse_dataframe(df)\n        except Exception as e:\n            # If bytes strongly indicate xlsx container, treat as real Excel parse failure.\n            if looks_like_zip:\n                hint = (\n                    \"请确认：(1) 文件为 .xlsx 格式；(2) 工作表不为空；(3) 文件未损坏。\"\n                    \"若为 .xls 格式，请另存为 .xlsx 后重试。\"\n                )\n                raise ValueError(f\"Excel 解析失败: {e}。{hint}\") from e\n            # For extension-only mismatch (e.g. csv named .xlsx), fallback to text parsing.\n            logger.warning(f\"扩展名为 .xlsx 但未解析为 Excel，将回退文本解析: {e}\")\n\n    # .xls not supported\n    if ext == \".xls\":\n        raise ValueError(\"仅支持 .xlsx 格式，请将 .xls 另存为 .xlsx 后重试\")\n\n    # CSV / text\n    for encoding in (\"utf-8\", \"gbk\"):\n        try:\n            text = data.decode(encoding)\n            break\n        except UnicodeDecodeError:\n            continue\n    else:\n        raise ValueError(\"无法识别文件编码，请使用 UTF-8 或 GBK\")\n\n    # Single-column (one value per line): bypass pandas to avoid sep=None inference issues","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/src/services/import_parser.py#L155-L191","documentation":"Raised when parsing bytes that carry the xlsx zip magic (PK\\x03\\x04) but openpyxl/pandas raises — i.e. a genuine broken Excel container. The hint distinguishes real xlsx corruption from a CSV merely named .xlsx (which falls back to text parsing with a warning instead).","triggerScenarios":"Corrupted xlsx (truncated upload); password-protected or non-standard Excel zip; .xls (OLE2) is NOT this path — only zip-magic files. Empty worksheet also lands here.","commonSituations":"File renamed from another format; upload truncated by proxy/body-size limits; Excel file saved with unusual compression; xlsx exported by third-party tools with non-standard structure.","solutions":["Re-open the file in Excel/WPS and re-save as .xlsx, then retry","If it is really .xls, convert: save as .xlsx (the error hint says exactly this)","Check the file wasn't truncated in transit — compare byte size with source","If password-protected, remove protection before import"],"exampleFix":"// not applicable — file-level fix (re-save/convert), not a code fix","handlingStrategy":"try-catch","validationCode":"def is_valid_xlsx(data: bytes) -> bool:\n    import openpyxl, io\n    try:\n        openpyxl.load_workbook(io.BytesIO(data), read_only=True)\n        return True\n    except Exception:\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    items = parse_import_from_bytes(data, fn)\nexcept ValueError as e:\n    if 'Excel 解析失败' in str(e):\n        prompt_user('请用 Excel 重新另存为 .xlsx 后再上传')\n    else:\n        raise","preventionTips":["Open the export in Excel and re-save as .xlsx before importing","Verify upload completeness (compare file size client vs server) to avoid truncated zips","Don't rename .xls to .xlsx — convert it properly"],"tags":["import","excel","xlsx","file-corruption"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}