{"record":{"id":"8e145dae65d9f7b9","repo":"langgenius/dify","slug":"document-already-finished","errorCode":"document_already_finished","errorMessage":"The document has been processed. Please refresh the page or go to the document details.","messagePattern":"The document has been processed\\. Please refresh the page or go to the document details\\.","errorType":"error_code","errorClass":"DocumentAlreadyFinishedError","httpStatus":400,"severity":"info","filePath":"api/controllers/console/datasets/datasets_document.py","lineNumber":713,"sourceCode":"        \"Indexing estimate calculated successfully\",\n        console_ns.models[IndexingEstimateResponse.__name__],\n    )\n    @console_ns.response(404, \"Document not found\")\n    @console_ns.response(400, \"Document already finished\")\n    @setup_required\n    @login_required\n    @account_initialization_required\n    @with_current_user\n    @with_current_tenant_id\n    @rbac_permission_required(RBACResourceScope.DATASET, RBACPermission.DATASET_CREATE_AND_MANAGEMENT)\n    @with_session\n    def get(self, session: Session, current_tenant_id: str, current_user: Account, dataset_id: UUID, document_id: UUID):\n        dataset_id_str = str(dataset_id)\n        document_id_str = str(document_id)\n        document = self.get_document(session, dataset_id_str, document_id_str, current_user, current_tenant_id)\n\n        if document.indexing_status in {IndexingStatus.COMPLETED, IndexingStatus.ERROR}:\n            raise DocumentAlreadyFinishedError()\n\n        data_process_rule = document.get_dataset_process_rule(session=session)\n        data_process_rule_dict: Mapping[str, Any] = data_process_rule.to_dict() if data_process_rule else {}\n\n        if document.data_source_type == \"upload_file\":\n            data_source_info = document.data_source_info_dict\n            if data_source_info and \"upload_file_id\" in data_source_info:\n                file_id = data_source_info[\"upload_file_id\"]\n\n                file = session.scalar(\n                    select(UploadFile)\n                    .where(UploadFile.tenant_id == document.tenant_id, UploadFile.id == file_id)\n                    .limit(1)\n                )\n\n                # raise error if file not found\n                if not file:\n                    raise NotFound(\"File not found.\")","sourceCodeStart":695,"sourceCodeEnd":731,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/datasets/datasets_document.py#L695-L731","documentation":"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.","triggerScenarios":"GET .../documents/{document_id}/indexing-estimate on a document whose indexing already completed or errored out.","commonSituations":"Stale UI still showing an 'Estimate' button after processing finished; polling retry; double submission after a long wait.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import requests\n\ndef document_is_inflight(base_url, headers, dataset_id, document_id) -> bool:\n    r = requests.get(\n        f\"{base_url}/console/api/datasets/{dataset_id}/documents/{document_id}/indexing-status\",\n        headers=headers,\n    )\n    r.raise_for_status()\n    return r.json().get('indexing_status') not in {'completed', 'error'}\n\nif not document_is_inflight(base, hdrs, dataset_id, document_id):\n    raise SystemExit('document already finished; estimate is not meaningful')","typeGuard":"def is_inflight(status: str) -> bool:\n    return status not in {'completed', 'error'}","tryCatchPattern":"try:\n    r = requests.get(f\"{base}/console/api/datasets/{dataset_id}/documents/{document_id}/indexing-estimate\",\n                     headers=hdrs)\n    r.raise_for_status()\nexcept requests.HTTPError as e:\n    if (e.response.json() or {}).get('code') == 'document_already_finished':\n        # read segment counts instead; do not retry estimate\n        r = requests.get(f\"{base}/console/api/datasets/{dataset_id}/documents/{document_id}/segments\",\n                         headers=hdrs)\n    else:\n        raise","preventionTips":["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."],"tags":["datasets","indexing","state","estimate"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}