langgenius/dify · info · DocumentAlreadyFinishedError
document_already_finished
document_already_finished
Error message
The document has been processed. Please refresh the page or go to the document details.
What it means
DocumentAlreadyFinishedError (HTTP 400, error_code=document_already_finished) raised in GET /datasets/{dataset_id}/documents/{document_id}/indexing-estimate when document.indexing_status is in {COMPLETED, ERROR}. Estimating cost for a finished document is meaningless, so the controller refuses.
Source
Thrown at api/controllers/console/datasets/datasets_document.py:713
"Indexing estimate calculated successfully",
console_ns.models[IndexingEstimateResponse.__name__],
)
@console_ns.response(404, "Document not found")
@console_ns.response(400, "Document already finished")
@setup_required
@login_required
@account_initialization_required
@with_current_user
@with_current_tenant_id
@rbac_permission_required(RBACResourceScope.DATASET, RBACPermission.DATASET_CREATE_AND_MANAGEMENT)
@with_session
def get(self, session: Session, current_tenant_id: str, current_user: Account, dataset_id: UUID, document_id: UUID):
dataset_id_str = str(dataset_id)
document_id_str = str(document_id)
document = self.get_document(session, dataset_id_str, document_id_str, current_user, current_tenant_id)
if document.indexing_status in {IndexingStatus.COMPLETED, IndexingStatus.ERROR}:
raise DocumentAlreadyFinishedError()
data_process_rule = document.get_dataset_process_rule(session=session)
data_process_rule_dict: Mapping[str, Any] = data_process_rule.to_dict() if data_process_rule else {}
if document.data_source_type == "upload_file":
data_source_info = document.data_source_info_dict
if data_source_info and "upload_file_id" in data_source_info:
file_id = data_source_info["upload_file_id"]
file = session.scalar(
select(UploadFile)
.where(UploadFile.tenant_id == document.tenant_id, UploadFile.id == file_id)
.limit(1)
)
# raise error if file not found
if not file:
raise NotFound("File not found.")View on GitHub (pinned to ef8544b173)
Solutions
- Refresh the document details page to reflect terminal status.
- Don't call the estimate endpoint once indexing_status is completed/error.
- Check indexing_status via the documents API before requesting an estimate.
- If you need post-hoc stats, read the document segments / token counts instead of the estimate endpoint.
Defensive patterns
Strategy: validation
Validate before calling
import requests
def document_is_inflight(base_url, headers, dataset_id, document_id) -> bool:
r = requests.get(
f"{base_url}/console/api/datasets/{dataset_id}/documents/{document_id}/indexing-status",
headers=headers,
)
r.raise_for_status()
return r.json().get('indexing_status') not in {'completed', 'error'}
if not document_is_inflight(base, hdrs, dataset_id, document_id):
raise SystemExit('document already finished; estimate is not meaningful') Type guard
def is_inflight(status: str) -> bool:
return status not in {'completed', 'error'} Try / catch
try:
r = requests.get(f"{base}/console/api/datasets/{dataset_id}/documents/{document_id}/indexing-estimate",
headers=hdrs)
r.raise_for_status()
except requests.HTTPError as e:
if (e.response.json() or {}).get('code') == 'document_already_finished':
# read segment counts instead; do not retry estimate
r = requests.get(f"{base}/console/api/datasets/{dataset_id}/documents/{document_id}/segments",
headers=hdrs)
else:
raise Prevention
- Hide the estimate action once indexing_status reaches completed/error.
- Poll indexing-status before requesting an estimate.
- Use the segments endpoint for post-hoc stats.
- Don't auto-retry estimate calls on terminal documents.
When it happens
Trigger: GET .../documents/{document_id}/indexing-estimate on a document whose indexing already completed or errored out.
Common situations: Stale UI still showing an 'Estimate' button after processing finished; polling retry; double submission after a long wait.
Related errors
- document_indexing
- indexing_estimate_error
- indexing_technique is required.
- File not found.
- The job does not exist.
AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12).
Data as JSON: /api/errors/8e145dae65d9f7b9.
Report an issue: GitHub.