{"record":{"id":"f4232845deb08fa2","repo":"odoo/odoo","slug":"import-file-has-no-content-or-is-corrupt","errorCode":null,"errorMessage":"Import file has no content or is corrupt","messagePattern":"Import file has no content or is corrupt","errorType":"validation","errorClass":"ImportValidationError","httpStatus":null,"severity":"error","filePath":"addons/base_import/models/base_import.py","lineNumber":1024,"sourceCode":"            fields-matching between the import's file data and the model's\n            columns.\n\n            If the headers are not requested (not options.has_headers),\n            returned ``matches`` and ``headers`` are both ``False``.\n\n            :param int count: number of preview lines to generate\n            :param options: format-specific options.\n                            CSV: {quoting, separator, headers}\n            :type options: {str, str, str, bool}\n            :returns: ``{fields, matches, headers, preview} | {error, preview}``\n            :rtype: {dict(str: dict(...)), dict(int, list(str)), list(str), list(list(str))} | {str, str}\n        \"\"\"\n        self.ensure_one()\n        fields_tree = self.get_fields_tree(self.res_model)\n        try:\n            file_length, data_rows = self._read_file(options)\n            if file_length <= 0:\n                raise ImportValidationError(_(\"Import file has no content or is corrupt\"))\n\n            preview = data_rows[:count]\n\n            # Get file headers\n            if options.get('has_headers') and preview:\n                # We need the header types before matching columns to fields\n                headers = preview.pop(0)\n                header_types = self._extract_headers_types(headers, preview, options)\n            else:\n                header_types, headers = {}, []\n\n            # Get matches: the ones already selected by the user or propose a new matching.\n            matches = {}\n            # If user checked to the advanced mode, we re-parse the file but we keep the mapping \"as is\".\n            # No need to make another mapping proposal\n            if options.get('keep_matches') and options.get('fields'):\n                for index, match in enumerate(options.get('fields', [])):\n                    if match:","sourceCodeStart":1006,"sourceCodeEnd":1042,"githubUrl":"https://github.com/odoo/odoo/blob/1e661df964b1b264c9cef3ab28430d4785be3fda/addons/base_import/models/base_import.py#L1006-L1042","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Open the file and confirm it actually contains data rows on the first sheet; re-export if empty.","For multi-sheet workbooks pass options['sheet'] with the correct sheet name (or pick it in the wizard).","Verify the file is not truncated/corrupt (re-download or re-create it) - a valid XLSX opens in Excel.","In custom flows, check row count client-side before upload (e.g. read the CSV and count non-blank lines)."],"exampleFix":"# before\nrecord.parse_preview(20, {})  # empty first sheet -> 'Import file has no content or is corrupt'\n\n# after: point at the sheet that has data\nrecord.parse_preview(20, {'sheet': 'Sheet2'})\n# or check emptiness first\nimport csv, io\nrows = [r for r in csv.reader(io.StringIO(text)) if any(c.strip() for c in r)]\nassert rows, 'refusing to upload an empty file'","handlingStrategy":"validation","validationCode":"import csv, io\n\ndef csv_has_rows(data: bytes, options: dict) -> bool:\n    text = data.decode(options.get('encoding') or 'utf-8-sig')\n    return any(any(c.strip() for c in row) for row in csv.reader(io.StringIO(text)))\n\ndef xlsx_has_rows(data: bytes, sheet: str | None = None) -> bool:\n    import openpyxl\n    book = openpyxl.load_workbook(io.BytesIO(data), data_only=True)\n    target = book[sheet] if sheet else book.worksheets[0]\n    return target.max_row > 0","typeGuard":null,"tryCatchPattern":"try:\n    record.parse_preview(count, options)\nexcept ImportValidationError as e:\n    if 'no content or is corrupt' in str(e):\n        return {'error': 'empty-file', 'hint': 'check sheet selection and re-export'}\n    raise","preventionTips":["Check row counts client-side before uploading.","For multi-sheet files always pass options['sheet'] explicitly.","Recreate files that fail to open cleanly in a spreadsheet editor (truncated transfers)."],"tags":["odoo","base-import","empty-file","csv","xlsx","validation"],"backgroundTag":null,"analyzedSha":"1e661df964b1b264c9cef3ab28430d4785be3fda","analyzedAt":"2026-08-15T05:22:16.142Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}