Skip to content
datahacks.dev
Excel

Why Excel Says the File Format or Extension Is Not Valid

Excel says the file format or extension is not valid when the content does not match the extension. Identify the real format from its first bytes and fix it.

6 min read
Summarize in AI
Flat illustration of a spreadsheet grid with a selected cell and a formula bar.

The message reads: "Excel cannot open the file 'report.xlsx' because the file format or file extension is not valid. Verify that the file has not been corrupted and that the file extension matches the format of the file." People take it to mean the file is damaged. It rarely is. It means the extension says one thing and the contents say another. This post shows how to read the real format from the first bytes, the usual ways a mismatch arises, and the fix for each. It is a spoke of understanding Excel errors when data comes from code.

What the extension promises

Each Excel extension promises a particular container.

ExtensionWhat it should be
.xlsx, .xlsmA zip archive of XML parts (Office Open XML)
.xlsA binary compound file (BIFF), the pre-2007 format
.xlsbA zip archive containing binary parts
.csvPlain text with delimiters

Excel checks the content against the extension when it opens the file. If a .xlsx is not a zip, or an .xls is not a compound file, it refuses with the format message. For .xls it sometimes opens the file anyway after a warning, "The file format and extension of 'x.xls' don't match", because it recognizes a CSV or HTML table inside and offers to open it, which is a courtesy for a very common mistake.

Read the first bytes

You can tell what a file is without opening it. Look at its first few bytes. In a terminal:

Shell
head -c 8 report.xlsx | xxd
file report.xlsx

In Python:

Python
with open("report.xlsx", "rb") as f:
    head = f.read(8)
print(head)

Compare the result with this table:

Starts withMeaning
50 4B 03 04 (PK followed by two bytes)A zip archive, so xlsx, xlsm, docx and similar
D0 CF 11 E0 A1 B1 1A E1A compound file, so a real .xls, or an encrypted .xlsx
3C 68 74 6D 6C (<html) or 3C 21 44 4F (<!DO)HTML saved with an Excel extension
3C 3F 78 6D 6C (<?xml)XML, possibly an XML Spreadsheet 2003 file
EF BB BF then textA UTF-8 CSV with a byte order mark
plain letters, commas, digitsA CSV or TSV
7B or 5B ({ or ``)JSON
25 50 44 46 (%PDF)A PDF

If the file size is zero, or a few hundred bytes of an HTML error page, the cause is a failed download or a script that wrote an error message into the output file. Open it in a text editor first: when the content is an HTML page from a login redirect, you have found the bug, and it has nothing to do with Excel.

The common causes

A script wrote HTML or CSV with an Excel name. A web application "exports to Excel" by echoing an HTML table with the header Content-Type: application/vnd.ms-excel and a .xls file name. Excel recognizes it and offers to open it, with a warning, but a .xlsx name on the same content gives the format error. A CSV renamed to .xlsx does the same.

An encrypted workbook. A password-protected xlsx is stored as a compound file, not a zip, so it starts with D0 CF 11 E0. Tools that expect a zip report a format problem, and Excel itself asks for the password ([password protected Excel files and scripts).

A truncated or empty download. The server returned fewer bytes than promised, or the proxy replaced the body. Compare the size with what the source reports, and re-download.

A file saved in the wrong format. Someone chose Save As, .xlsx, but the format drop-down said CSV. It happens with some tools that apply the extension without converting.

A renamed file. Changing .xls to .xlsx in Explorer does not convert anything. The content is still the old binary format and Excel rejects it.

A security setting. Excel's file block settings can refuse older formats; the message then differs and refers to the Trust Center.

Fix it

Decide by what the first bytes say.

  • Zip, but the name is wrong: rename to .xlsx. Check the contents with unzip -l report.xlsx: a real workbook lists [Content_Types].xml, xl/workbook.xml and xl/worksheets/.

  • Compound file with an .xlsx name: rename to .xls, or open it and save as xlsx. If it asks for a password, it is encrypted.

  • HTML: rename to .html and open it in a browser. If it is an error page, fix the request. If it is a table, read it with pandas.read_html, or open it in Excel via Data, From Web, or save the page as csv.

  • CSV or TSV: rename to .csv and open it through Data, From Text/CSV so you choose the delimiter and the encoding (Excel and CSV files shared with other tools).

  • XML: if it is the XML Spreadsheet 2003 format, rename to .xml and open it in Excel; otherwise it is data to parse.

Then repair the producer. If your code writes the file, use a real writer: openpyxl or XlsxWriter for xlsx, or to_excel in pandas. Writing HTML and naming it .xls is a shortcut with known costs, including this message, security warnings and lost types. Set the response header correctly if serving the file from a web app: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet for xlsx.

Add a check to the pipeline

When files arrive from outside, check before reading. A small function can name the real type:

Python
def sniff(path):
    with open(path, "rb") as f:
        head = f.read(8)
    if head.startswith(b"PK\x03\x04"):
        return "zip (xlsx or similar)"
    if head.startswith(b"\xd0\xcf\x11\xe0"):
        return "compound file (xls or encrypted)"
    if head.lstrip().lower().startswith((b"<html", b"<!doc")):
        return "html"
    return "other"

Call it before read_excel and fail with a message that says what the file is. A pipeline that reports "expected xlsx, got html" saves the hour spent staring at a traceback from deep inside a library. The same check belongs on any upload endpoint, which should also verify size and content before processing (checking an Excel upload before reading it).

Python errors that mean the same thing

The same mismatch appears in code as different messages:

  • zipfile.BadZipFile: File is not a zip file from openpyxl on a non-zip (fixing BadZipFile when reading an XLSX).

  • xlrd.biffh.XLRDError: Excel xlsx file; not supported from xlrd given an xlsx (the Python xlrd error).

  • openpyxl.utils.exceptions.InvalidFileException for an unsupported extension such as .xls.

Each of these says "I was handed something other than what the name promised". Reading the first bytes answers all of them.

When the format message hides a different problem

The file really is corrupt. A zip whose end record is missing starts with PK but fails to open. unzip -t file.xlsx tests it (Excel cannot open the file because it is corrupt).

The workbook opens but complains. A message about unreadable content is a different problem, usually invalid XML inside a valid package.

Protected View blocks it. A file from the internet opens read-only with a yellow bar. That is a security feature, not a format problem.

The path is wrong. A shortcut or a network file that has moved can produce misleading messages. Try copying the file locally and opening it from there.

See Microsoft's page on file formats supported in Excel and the open standard in ECMA-376 Office Open XML. To convert a small CSV, use the CSV to JSON converter.

Also inDebugging
Share

Keep reading

Get new articles by email

We send one email when a new article is published. No spam.

Unsubscribe in one click. No spam, ever.