{"record":{"id":"d59f3ef65d7ef622","repo":"apache/superset","slug":"unexpected-no-file-extension-found","errorCode":null,"errorMessage":"Unexpected no file extension found","messagePattern":"Unexpected no file extension found","errorType":"exception","errorClass":"DatabaseUploadFailed","httpStatus":422,"severity":"error","filePath":"superset/commands/database/uploaders/columnar_reader.py","lineNumber":87,"sourceCode":"        ) as ex:\n            raise DatabaseUploadFailed(\n                message=_(\"Parsing error: %(error)s\", error=str(ex))\n            ) from ex\n        except Exception as ex:\n            raise DatabaseUploadFailed(_(\"Error reading Columnar file\")) from ex\n\n    @staticmethod\n    def _yield_files(file: FileStorage) -> Generator[IO[bytes], None, None]:\n        \"\"\"\n        Yields files from the provided file. If the file is a zip file, it yields each\n        file within the zip file. If it's a single file, it yields the file itself.\n\n        :param file: The file to yield files from.\n        :return: A generator that yields files.\n        \"\"\"\n        file_suffix = Path(file.filename).suffix\n        if not file_suffix:\n            raise DatabaseUploadFailed(_(\"Unexpected no file extension found\"))\n        file_suffix = file_suffix[1:]  # remove the dot\n        if file_suffix == \"zip\":\n            if not is_zipfile(file):\n                raise DatabaseUploadFailed(_(\"Not a valid ZIP file\"))\n            try:\n                with ZipFile(file) as zip_file:\n                    # guard against decompression bombs before reading entries,\n                    # mirroring the importer path\n                    try:\n                        check_is_safe_zip(zip_file)\n                    except SupersetException as ex:\n                        raise DatabaseUploadFailed(str(ex)) from ex\n                    # check if all file types are of the same extension\n                    file_suffixes = {Path(name).suffix for name in zip_file.namelist()}\n                    if len(file_suffixes) > 1:\n                        raise DatabaseUploadFailed(\n                            _(\"ZIP file contains multiple file types\")\n                        )","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/commands/database/uploaders/columnar_reader.py#L69-L105","documentation":"DatabaseUploadFailed ('Unexpected no file extension found') raised in ColumnarReader._yield_files when Path(file.filename).suffix is empty. The Columnar reader dispatches on the file extension (zip vs single Parquet), so a file with no extension cannot be routed and the upload is rejected before any parsing.","triggerScenarios":"Uploading a file whose Flask FileStorage filename has no dot-separated suffix, e.g. 'data', 'output', or a client that sends filename without extension; also filenames ending in a dot ('data.') yield an empty suffix.","commonSituations":"Programmatic API uploads (POST to /api/v1/database/<id>/upload/ with form-data) where the filename field is omitted or set to a bare name; temp files renamed without extension; some browsers/SDKs defaulting to blob filenames.","solutions":["Rename the file to include the correct extension, e.g. data.parquet (or data.zip for archives)","If uploading programmatically, set the multipart filename explicitly: files={'file': ('data.parquet', fh, 'application/octet-stream')}","Validate the extension client-side before starting the upload"],"exampleFix":"# before\ncurl -F 'file=@/tmp/tmp8123' ...\n# after\ncurl -F 'file=@/tmp/tmp8123;filename=data.parquet' ...","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef has_extension(filename: str | None) -> bool:\n    return bool(filename and Path(filename).suffix)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always name uploads with the real extension (.parquet/.zip)","Set multipart filename explicitly in API clients","Client-side check: reject files without a suffix before POSTing"],"tags":["file-upload","validation","filename","parquet"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}