Uahh/ToastFish · error

ex.Message, "Excel read error"

Error message

ex.Message, "Excel read error"

What it means

ImportExcel wraps workbook opening in try/catch and, when neither XSSFWorkbook nor HSSFWorkbook can parse the file, shows a modal 'Excel read error' dialog with the raw exception message. It means the file at `path` could not be opened as either OOXML (.xlsx) or legacy BIFF (.xls) format. The method then returns an empty List<Word> instead of the expected word list.

Solutions

  1. Open the file in Microsoft Excel/LibreOffice and re-save it as a genuine .xlsx (or .xls) file
  2. Verify the file extension matches the actual format (open the first bytes; .xlsx is a ZIP starting with PK)
  3. Ensure the file is fully downloaded/copied and not zero-length or locked by another process
  4. Wrap the ImportExcel call and check the returned list count; treat an empty list as 'import failed' rather than 'no words'

Example fix

// before
object lstObj = Log.ImportExcel(FileName);
string typeObj = lstObj.ToString();
// after
var lstObj = Log.ImportExcel(FileName);
if (lstObj == null || lstObj.Count == 0)
{
    MessageBox.Show("File could not be read as xlsx/xls. Re-save it as a real Excel workbook.");
    return;
}
Defensive patterns

Strategy: validation

Validate before calling

var fi = new FileInfo(path);
if (!fi.Exists || fi.Length < 512) throw new InvalidDataException("不是有效的Excel文件");
using (var peek = File.OpenRead(path)) { int b0 = peek.ReadByte(); int b1 = peek.ReadByte();
    if (b0 != 'P' && b0 != 0xD0) throw new InvalidDataException("文件不是 xlsx (ZIP) 或 xls (OLE) 格式"); }

Type guard

static bool LooksLikeExcel(string path) { try { var b = File.ReadAllBytes(path).Take(8).ToArray();
    return b.Length >= 4 && (b[0]==0x50 && b[1]==0x4B) || (b[0]==0xD0 && b[1]==0xCF); } catch { return false; } }

Try / catch

try { var list = Log.ImportExcel(path); }
catch (Exception ex) { MessageBox.Show($"Excel读取失败:{ex.Message}"); }
finally { /* treat empty list as failure */ }

Prevention

When it happens

Trigger: CreateLog.ImportExcel(path) is called with a file that is not a real Excel workbook: a renamed file, an HTML/CSV file exported as .xls, a password-protected or corrupted workbook, or a file locked/zero bytes. The XSSF parse fails silently, the HSSF fallback throws, and the catch shows the dialog.

Common situations: Users rename .csv or .html exports to .xlsx/.xls; files downloaded incompletely; OneDrive/网络 disks handing out placeholder files; Excel files saved in formats NPOI cannot read (e.g. .xlsb, encrypted workbooks); the FileStream itself throws because another process holds an incompatible lock.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of Uahh/ToastFish@2508784a66 (2026-09-15). Data as JSON: /api/errors/c077c05db2eef740. Report an issue: GitHub.

Appendix: source

Thrown at Model/Log/CreateLog.cs:122

                // Try to read WorkBook as XLSX:
                try
                {
                    WorkBook = new XSSFWorkbook(fs);
                }
                catch
                {
                    WorkBook = null;
                }

                // If reading fails, try to read WorkBook as XLS:
                if (WorkBook == null)
                {
                    WorkBook = new HSSFWorkbook(fs);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Excel read error", MessageBoxButton.OK, MessageBoxImage.Error);
                return WordList;
            }

            ISheet Sheet = WorkBook.GetSheetAt(0);
            IRow FirstRow = Sheet.GetRow(0);
            if(FirstRow.GetCell(0).ToString() == "英语")
            {
                int RowCount = Sheet.LastRowNum;
                for (int i = 1; i <= RowCount; i++)
                {
                    IRow Row = Sheet.GetRow(i);
                    Word TempWord = new Word();
                    if (Row == null)
                        continue;
                    TempWord.headWord = Row.GetCell(1).ToString();
                    TempWord.tranCN = Row.GetCell(2).ToString();
                    TempWord.ukPhone = Row.GetCell(3).ToString();
                    TempWord.usPhone = Row.GetCell(4).ToString();

View on GitHub (pinned to 2508784a66)