{"record":{"id":"473ad9798b5d8d12","repo":"langgenius/dify","slug":"invalid-file-type-only-csv-files-are-allowed","errorCode":null,"errorMessage":"Invalid file type. Only CSV files are allowed","messagePattern":"Invalid file type\\. Only CSV files are allowed","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"api/controllers/console/app/annotation.py","lineNumber":478,"sourceCode":"    @edit_permission_required\n    @rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_EDIT)\n    @with_session\n    def post(self, session: Session, app_id: UUID):\n        from configs import dify_config\n\n        # check file\n        if \"file\" not in request.files:\n            raise NoFileUploadedError()\n\n        if len(request.files) > 1:\n            raise TooManyFilesError()\n\n        # get file from request\n        file = request.files[\"file\"]\n\n        # check file type\n        if not file.filename or not file.filename.lower().endswith(\".csv\"):\n            raise ValueError(\"Invalid file type. Only CSV files are allowed\")\n\n        # Check file size before processing\n        file.stream.seek(0, 2)  # Seek to end of file\n        file_size = file.stream.tell()\n        file.stream.seek(0)  # Reset to beginning\n\n        max_size_bytes = dify_config.ANNOTATION_IMPORT_FILE_SIZE_LIMIT * 1024 * 1024\n        if file_size > max_size_bytes:\n            abort(\n                413,\n                f\"File size exceeds maximum limit of {dify_config.ANNOTATION_IMPORT_FILE_SIZE_LIMIT}MB. \"\n                f\"Please reduce the file size and try again.\",\n            )\n\n        if file_size == 0:\n            raise ValueError(\"The uploaded file is empty\")\n\n        return dump_response(","sourceCodeStart":460,"sourceCodeEnd":496,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/app/annotation.py#L460-L496","documentation":"Raised by AnnotationBatchImportApi.post when the uploaded file's filename is missing (None/empty) or does not end with '.csv' (case-insensitive). This is a raw Python ValueError, not a BaseHTTPException, so it is translated to a 400 by Flask's default error handler rather than Dify's structured error envelope. Only CSV files are accepted for annotation batch import.","triggerScenarios":"Uploading .xlsx, .tsv, .txt, .json, or any non-.csv extension; uploading a file whose filename attribute is empty (some clients omit Content-Disposition filename); uploading a Blob without a filename in JS FormData.","commonSituations":"User exports Excel instead of CSV; frontend creates a Blob and appends without a third filename argument (form.append('file', blob) — no filename); macOS hiding the extension causes the saved file to be named 'annotations' with no suffix.","solutions":["Convert the source data to CSV before uploading (Excel: File > Save As > CSV UTF-8).","When using FormData.append in JS, pass the filename explicitly: form.append('file', blob, 'annotations.csv').","Strip query strings or fragments from the filename before upload.","If your pipeline produces another format, add a pre-upload conversion step."],"exampleFix":"// before\nform.append('file', blob);\n\n// after\nform.append('file', blob, 'annotations.csv');","handlingStrategy":"validation","validationCode":"function assertCsv(file) {\n  if (!file || !file.name) throw new Error('File must have a name');\n  if (!file.name.toLowerCase().endsWith('.csv')) throw new Error('Only .csv files are accepted');\n  return file;\n}","typeGuard":"const isCsv = (file) => !!file && !!file.name && file.name.toLowerCase().endsWith('.csv');","tryCatchPattern":"try { await fetch(url, { method: 'POST', body: form }); }\ncatch (e) { if (/Invalid file type/.test(e.message)) alert('Please upload a .csv file.'); }","preventionTips":["Always pass a filename as the third arg to FormData.append.","Restrict the file input with accept='.csv'.","Convert Excel/TSV exports to CSV before upload."],"tags":["annotations","file-upload","csv","validation","console-api"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}