{"record":{"id":"03e4facb6ddb6459","repo":"ZhuLinsen/daily_stock_analysis","slug":"xlsx-xls-xlsx","errorCode":null,"errorMessage":"仅支持 .xlsx 格式，请将 .xls 另存为 .xlsx 后重试","messagePattern":"仅支持 \\.xlsx 格式，请将 \\.xls 另存为 \\.xlsx 后重试","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/services/import_parser.py","lineNumber":179,"sourceCode":"            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\n    # e.g. \"00700\\n600519\" or \"code\\n00700\" - pandas with sep=None can produce wrong results\n    lines = [ln.strip() for ln in text.strip().splitlines() if ln.strip()]\n    if _should_use_single_column_fast_path(lines):\n        rows = [[ln] for ln in lines]\n        df = pd.DataFrame(rows)\n        first_row = [str(x).strip().lower() for x in df.iloc[0].tolist()]","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/src/services/import_parser.py#L161-L197","documentation":"Hard rejection in parse_import_from_bytes for files with .xls extension: the parser supports only .xlsx (openpyxl reads zip-based OOXML), not the legacy binary .xls (OLE2/BIFF) format.","triggerScenarios":"Uploading a file named *.xls (legacy Excel 97-2003 format, or any file given that extension).","commonSituations":"Old broker exports still shipped as .xls; user renames .xls to .xlsx (which then takes the zip-magic fallback path, not this one); corporate templates in legacy format.","solutions":["Open the .xls in Excel/WPS and 'Save As' -> .xlsx, then re-upload","Or copy the data into a CSV and upload that","If automating, convert with LibreOffice headless: soffice --headless --convert-to xlsx file.xls"],"exampleFix":"$ soffice --headless --convert-to xlsx portfolio.xls\n# then upload portfolio.xlsx","handlingStrategy":"validation","validationCode":"if filename and filename.rsplit('.',1)[-1].lower() == 'xls':\n    prompt_user('检测到 .xls，请另存为 .xlsx 或导出 CSV 后重试')","typeGuard":"def is_xls(filename: str) -> bool:\n    return (filename or '').rsplit('.', 1)[-1].lower() == 'xls'","tryCatchPattern":null,"preventionTips":["Filter the file picker to .xlsx and .csv only","Convert legacy .xls exports at the source (Excel/LibreOffice) before import"],"tags":["import","excel","xls","unsupported-format"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}