ZhuLinsen/daily_stock_analysis · error · ValueError
Excel 解析失败: {e}。请确认:(1) 文件为 .xlsx 格式;(2) 工作表不为空;(3) 文件未损坏。若为
Error message
Excel 解析失败: {e}。请确认:(1) 文件为 .xlsx 格式;(2) 工作表不为空;(3) 文件未损坏。若为 .xls 格式,请另存为 .xlsx 后重试。 What it means
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).
Source
Thrown at src/services/import_parser.py:173
# Use header=None to avoid silently consuming the first data row as column names
# when the sheet has no header row. We detect headers the same way as the CSV path.
df = pd.read_excel(io.BytesIO(data), sheet_name=0, engine="openpyxl", header=None, dtype=str)
if df is None or df.empty:
return []
df = df.fillna("")
first_row = [str(x).strip().lower() for x in df.iloc[0].tolist()]
if any(c in _CODE_ALIASES or c in _NAME_ALIASES for c in first_row):
df.columns = df.iloc[0]
df = df.iloc[1:].reset_index(drop=True)
return _parse_dataframe(df)
except Exception as e:
# If bytes strongly indicate xlsx container, treat as real Excel parse failure.
if looks_like_zip:
hint = (
"请确认:(1) 文件为 .xlsx 格式;(2) 工作表不为空;(3) 文件未损坏。"
"若为 .xls 格式,请另存为 .xlsx 后重试。"
)
raise ValueError(f"Excel 解析失败: {e}。{hint}") from e
# For extension-only mismatch (e.g. csv named .xlsx), fallback to text parsing.
logger.warning(f"扩展名为 .xlsx 但未解析为 Excel,将回退文本解析: {e}")
# .xls not supported
if ext == ".xls":
raise ValueError("仅支持 .xlsx 格式,请将 .xls 另存为 .xlsx 后重试")
# CSV / text
for encoding in ("utf-8", "gbk"):
try:
text = data.decode(encoding)
break
except UnicodeDecodeError:
continue
else:
raise ValueError("无法识别文件编码,请使用 UTF-8 或 GBK")
# Single-column (one value per line): bypass pandas to avoid sep=None inference issuesView on GitHub (pinned to 5159bd72e8)
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
Example fix
// not applicable — file-level fix (re-save/convert), not a code fix
Defensive patterns
Strategy: try-catch
Validate before calling
def is_valid_xlsx(data: bytes) -> bool:
import openpyxl, io
try:
openpyxl.load_workbook(io.BytesIO(data), read_only=True)
return True
except Exception:
return False Try / catch
try:
items = parse_import_from_bytes(data, fn)
except ValueError as e:
if 'Excel 解析失败' in str(e):
prompt_user('请用 Excel 重新另存为 .xlsx 后再上传')
else:
raise Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- 仅支持 .xlsx 格式,请将 .xls 另存为 .xlsx 后重试
- invalid_import_file
- 未安装 Futu OpenAPI SDK;请先执行 `pip install "futu-api==10.8.6808"
- 加载 Futu OpenAPI SDK 失败: {exc}
- 请安装 schedule 库: pip install schedule
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/610d297ead4b0042.
Report an issue: GitHub.