odoo/odoo · error · ImportValidationError

Import file has no content or is corrupt

Error message

Import file has no content or is corrupt

What it means

Raised in parse_preview when _read_file() succeeds but reports file_length <= 0, meaning the reader found zero data rows (or a negative count from an empty sheet). It guards the preview step against empty or structurally broken files before any field matching happens.

Source

Thrown at addons/base_import/models/base_import.py:1024

            fields-matching between the import's file data and the model's
            columns.

            If the headers are not requested (not options.has_headers),
            returned ``matches`` and ``headers`` are both ``False``.

            :param int count: number of preview lines to generate
            :param options: format-specific options.
                            CSV: {quoting, separator, headers}
            :type options: {str, str, str, bool}
            :returns: ``{fields, matches, headers, preview} | {error, preview}``
            :rtype: {dict(str: dict(...)), dict(int, list(str)), list(str), list(list(str))} | {str, str}
        """
        self.ensure_one()
        fields_tree = self.get_fields_tree(self.res_model)
        try:
            file_length, data_rows = self._read_file(options)
            if file_length <= 0:
                raise ImportValidationError(_("Import file has no content or is corrupt"))

            preview = data_rows[:count]

            # Get file headers
            if options.get('has_headers') and preview:
                # We need the header types before matching columns to fields
                headers = preview.pop(0)
                header_types = self._extract_headers_types(headers, preview, options)
            else:
                header_types, headers = {}, []

            # Get matches: the ones already selected by the user or propose a new matching.
            matches = {}
            # If user checked to the advanced mode, we re-parse the file but we keep the mapping "as is".
            # No need to make another mapping proposal
            if options.get('keep_matches') and options.get('fields'):
                for index, match in enumerate(options.get('fields', [])):
                    if match:

View on GitHub (pinned to 1e661df964)

Solutions

  1. Open the file and confirm it actually contains data rows on the first sheet; re-export if empty.
  2. For multi-sheet workbooks pass options['sheet'] with the correct sheet name (or pick it in the wizard).
  3. Verify the file is not truncated/corrupt (re-download or re-create it) - a valid XLSX opens in Excel.
  4. In custom flows, check row count client-side before upload (e.g. read the CSV and count non-blank lines).

Example fix

# before
record.parse_preview(20, {})  # empty first sheet -> 'Import file has no content or is corrupt'

# after: point at the sheet that has data
record.parse_preview(20, {'sheet': 'Sheet2'})
# or check emptiness first
import csv, io
rows = [r for r in csv.reader(io.StringIO(text)) if any(c.strip() for c in r)]
assert rows, 'refusing to upload an empty file'
Defensive patterns

Strategy: validation

Validate before calling

import csv, io

def csv_has_rows(data: bytes, options: dict) -> bool:
    text = data.decode(options.get('encoding') or 'utf-8-sig')
    return any(any(c.strip() for c in row) for row in csv.reader(io.StringIO(text)))

def xlsx_has_rows(data: bytes, sheet: str | None = None) -> bool:
    import openpyxl
    book = openpyxl.load_workbook(io.BytesIO(data), data_only=True)
    target = book[sheet] if sheet else book.worksheets[0]
    return target.max_row > 0

Try / catch

try:
    record.parse_preview(count, options)
except ImportValidationError as e:
    if 'no content or is corrupt' in str(e):
        return {'error': 'empty-file', 'hint': 'check sheet selection and re-export'}
    raise

Prevention

When it happens

Trigger: Uploading an empty CSV/XLSX/ODS, a file whose first sheet has no rows (data on another sheet without options['sheet'] set), a CSV containing only blank lines, or a file so corrupt readers return max_row == 0.

Common situations: User exports a filtered view that happens to contain no rows; file was truncated during transfer; XLSX with data only on 'Sheet2' while the importer defaults to the first sheet; whitespace-only CSV.

Related errors


AI-assisted analysis of odoo/odoo@1e661df964 (2026-08-15). Data as JSON: /api/errors/f4232845deb08fa2. Report an issue: GitHub.