langgenius/dify · error · NotFound
UploadFile not found.
Error message
UploadFile not found.
What it means
Raised by the segment batch-import POST endpoint when the supplied upload_file_id does not resolve to a row in the UploadFile table. The controller verifies dataset and document first, then loads the UploadFile by id; a None result triggers flask-restx NotFound (HTTP 404). It means the file referenced by the request body was never uploaded, was deleted, or does not belong to the tenant scope the query sees.
Solutions
- Re-run the file upload and capture the returned upload_file_id, then re-send the batch_import request with that fresh id.
- Confirm the upload_file_id belongs to the same tenant by checking the upload history endpoint before submitting the import.
- If the file was intentionally deleted, upload a new CSV and use its id.
Example fix
// before
POST .../segments/batch_import body: {"upload_file_id": "<stale id>"}
// after
1) POST .../files/upload (multipart: the .csv) -> {"id": "<new_id>"}
2) POST .../segments/batch_import body: {"upload_file_id": "<new_id>"} Defensive patterns
Strategy: validation
Validate before calling
// Before POSTing batch_import, verify the upload file id resolves to a CSV.
async function safeBatchImport(uploadFileId, ids) {
const fileMeta = await fetch(`/console/api/files/upload/${uploadFileId}`).then(r => r.ok ? r.json() : null);
if (!fileMeta) throw new Error('upload_file_id is invalid; re-upload the CSV first');
return fetch(`/console/api/datasets/${ids.dataset}/documents/${ids.document}/segments/batch_import`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({upload_file_id: uploadFileId}),
});
} Type guard
function isValidUploadFileId(id) {
return typeof id === 'string' && /^[0-9a-fA-F-]{36}$/.test(id) && id !== '00000000-0000-0000-0000-000000000000';
} Try / catch
try {
await batchImport(uploadFileId, ids);
} catch (e) {
if (e.status === 404 && /UploadFile not found/.test(e.message)) {
// re-upload then retry once with the new id
const fresh = await uploadCsv(file);
await batchImport(fresh.id, ids);
} else throw e;
} Prevention
- Capture and store the upload_file_id from the upload response immediately, do not hardcode.
- Run the import right after the upload to avoid background cleanup removing the file.
- Confirm the id belongs to the same tenant before submitting.
When it happens
Trigger: POST /console/api/datasets/{dataset_id}/documents/{document_id}/segments/batch_import with a Body.upload_file_id that does not exist in the UploadFile table. Common when the upload step returns an id but it has since been removed, when an id from a different workspace is reused, or when the frontend sends the field as null/empty after a failed upload.
Common situations: Uploading a CSV through the file-upload endpoint, then waiting long enough that the file is cleaned up before the import POST fires; copy-pasting an upload_file_id from another tenant; the upload step silently failed and returned no id while the UI still submits.
Related errors
- The job does not exist.
- API template not found.
- Dataset not found.
- Document not found.
- Child chunk not found.
AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12).
Data as JSON: /api/errors/af1f2d99d6ba33a5.
Report an issue: GitHub.
Appendix: source
Thrown at api/controllers/console/datasets/datasets_segments.py:647
dataset_id: UUID,
document_id: UUID,
):
# check dataset
dataset_id_str = str(dataset_id)
dataset = DatasetService.get_dataset(dataset_id_str, session)
if not dataset:
raise NotFound("Dataset not found.")
# check document
document_id_str = str(document_id)
document = DocumentService.get_document(dataset_id_str, document_id_str, session=session)
if not document:
raise NotFound("Document not found.")
upload_file_id = req_data.upload_file_id
upload_file = session.scalar(select(UploadFile).where(UploadFile.id == upload_file_id).limit(1))
if not upload_file:
raise NotFound("UploadFile not found.")
# check file type
if not upload_file.name or not upload_file.name.lower().endswith(".csv"):
raise ValueError("Invalid file type. Only CSV files are allowed")
try:
# async job
job_id = str(uuid.uuid4())
indexing_cache_key = f"segment_batch_import_{job_id}"
# send batch add segments task
redis_client.setnx(indexing_cache_key, "waiting")
batch_create_segment_to_index_task.delay(
job_id,
upload_file_id,
dataset_id_str,
document_id_str,
current_tenant_id,
current_user.id,View on GitHub (pinned to ef8544b173)