langgenius/dify · error · ValueError

The uploaded file is empty

Error message

The uploaded file is empty

What it means

Raised by AnnotationBatchImportApi.post after the size check, when file_size == 0 bytes. Like the file-type check this is a raw ValueError, surfaced as a 400 through Flask's default handler rather than Dify's structured envelope. It catches CSVs that passed the extension check but contain no data.

Source

Thrown at api/controllers/console/app/annotation.py:494

        # 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:
            abort(
                413,
                f"File size exceeds maximum limit of {dify_config.ANNOTATION_IMPORT_FILE_SIZE_LIMIT}MB. "
                f"Please reduce the file size and try again.",
            )

        if file_size == 0:
            raise ValueError("The uploaded file is empty")

        return dump_response(
            AnnotationBatchImportResponse,
            AppAnnotationService.batch_import_app_annotations(str(app_id), file, session),
        )


@console_ns.route("/apps/<uuid:app_id>/annotations/batch-import-status/<uuid:job_id>")
class AnnotationBatchImportStatusApi(Resource):
    @console_ns.doc("get_batch_import_status")
    @console_ns.doc(description="Get status of batch import job")
    @console_ns.doc(params={"app_id": "Application ID", "job_id": "Job ID"})
    @console_ns.response(
        200, "Job status retrieved successfully", console_ns.models[AnnotationJobStatusDetailResponse.__name__]
    )
    @console_ns.response(403, "Insufficient permissions")
    @setup_required
    @login_required

View on GitHub (pinned to ef8544b173)

Solutions

  1. Open the CSV locally and confirm it contains at least a header row and data.
  2. If using a script to generate the file, raise an error in the script when zero rows are produced so you never send an empty file.
  3. Re-run the export and verify the file size on disk is > 0 before uploading.
  4. Check the upload client for truncation (e.g., incorrect binary mode in transfer).

Example fix

# before
with open('annotations.csv', 'w') as f:  # accidentally creates empty file
    pass

# after
import os
assert os.path.getsize('annotations.csv') > 0, 'CSV is empty; regenerate it'
Defensive patterns

Strategy: validation

Validate before calling

function assertNonEmptyFile(file) {
  if (file.size === 0) throw new Error('CSV file is empty');
  return file;
}

Type guard

const isNonEmptyFile = (file) => !!file && file.size > 0;

Try / catch

try { await fetch(url, { method: 'POST', body: form }); }
catch (e) { if (/empty/.test(e.message)) alert('The selected CSV has no content.'); }

Prevention

When it happens

Trigger: Uploading a newly-created empty CSV file (just headers absent); a truncated upload where the connection dropped mid-transfer leaving a zero-byte temp file; a template file that was never populated; a symbolic link pointing to /dev/null.

Common situations: Automated export pipeline writes the file but the source query returns zero rows and the writer leaves the file empty; CI test fixture checked in as an empty file; FTP/SFTP transfer mode stripping all content.

Related errors


AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12). Data as JSON: /api/errors/1cf626bc936a7050. Report an issue: GitHub.