langgenius/dify · error · NoFileUploadedError
no_file_uploaded
no_file_uploaded
Error message
Please upload your file.
What it means
Raised by POST /console/apps/{app_id}/annotations/batch-import (AnnotationBatchImportApi.post) when the multipart request contains no entry under the 'file' key in request.files. The controller guards this before any parsing, rate-limit, or billing work. It surfaces as a 400 with error_code 'no_file_uploaded' via NoFileUploadedError (BaseHTTPException).
Source
Thrown at api/controllers/console/app/annotation.py:468
@console_ns.response(403, "Insufficient permissions")
@console_ns.response(400, "No file uploaded or too many files")
@console_ns.response(413, "File too large")
@console_ns.response(429, "Too many requests or concurrent imports")
@setup_required
@login_required
@account_initialization_required
@cloud_edition_billing_resource_check("annotation")
@annotation_import_rate_limit
@annotation_import_concurrency_limit
@edit_permission_required
@rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_EDIT)
@with_session
def post(self, session: Session, app_id: UUID):
from configs import dify_config
# check file
if "file" not in request.files:
raise NoFileUploadedError()
if len(request.files) > 1:
raise TooManyFilesError()
# get file from request
file = request.files["file"]
# check file type
if not file.filename or not file.filename.lower().endswith(".csv"):
raise ValueError("Invalid file type. Only CSV files are allowed")
# Check file size before processing
file.stream.seek(0, 2) # Seek to end of file
file_size = file.stream.tell()
file.stream.seek(0) # Reset to beginning
max_size_bytes = dify_config.ANNOTATION_IMPORT_FILE_SIZE_LIMIT * 1024 * 1024
if file_size > max_size_bytes:View on GitHub (pinned to ef8544b173)
Solutions
- Ensure the request is multipart/form-data and includes exactly one file part under the field name 'file'.
- Verify the client code: in JS use FormData and append('file', fileBlob, 'annotations.csv'); in cURL use -F 'file=@path/to/annotations.csv'.
- Double-check that no proxy/gateway strips multipart bodies or renames form fields.
- Confirm the file actually exists on disk before attaching (a missing source path can silently produce an empty form).
Example fix
// before
const res = await fetch(url, { method: 'POST', body: JSON.stringify({}) });
// after
const form = new FormData();
form.append('file', csvFile, 'annotations.csv');
const res = await fetch(url, { method: 'POST', body: form }); Defensive patterns
Strategy: validation
Validate before calling
function buildAnnotationImportForm(file) {
if (!file) throw new Error('A CSV File is required');
const form = new FormData();
form.append('file', file, file.name || 'annotations.csv');
return form;
} Type guard
function isSingleCsvFile(files) {
return Array.isArray(files) ? files.length === 1 && files[0].name.toLowerCase().endsWith('.csv') : !!files && files.name.toLowerCase().endsWith('.csv');
} Try / catch
try {
const res = await fetch(url, { method: 'POST', body: form });
if (res.status === 400) {
const body = await res.json();
if (body.code === 'no_file_uploaded') showMessage('Attach a CSV file first.');
}
} catch (e) { /* network */ } Prevention
- Always use FormData and append under the exact field name 'file'.
- Assert the file object is non-null before constructing the request.
- Set the request Content-Type implicitly via FormData (do not set it manually).
When it happens
Trigger: Calling the annotation batch-import endpoint with a request body that omits the file part entirely, or sends the file under a different field name (e.g., 'csv', 'upload'). Also triggered by sending application/json instead of multipart/form-data, since Flask leaves request.files empty.
Common situations: Frontend uploader attaches the File object under the wrong form field name; cURL/Postman request sent as JSON body rather than multipart form-data; automated script forgetting to open the file in binary 'rb' mode; the file input being disabled or skipped in the UI.
Related errors
- too_many_files
- Invalid file type. Only CSV files are allowed
- The uploaded file is empty
- no_audio_uploaded
- unsupported_audio_type
AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12).
Data as JSON: /api/errors/590e570b179ad3ea.
Report an issue: GitHub.