{"record":{"id":"0dd1cc6167e9c124","repo":"BerriAI/litellm","slug":"cannot-delete-file-file-id-the-file-is-referenc","errorCode":null,"errorMessage":"Cannot delete file {file_id}. The file is referenced by {count} batch(es) in non-terminal state: {batch_statuses}. To delete this file before complete cost tracking, please delete or cancel the referencing batch(es) first. Alternatively, wait for all batches to complete and for cost to be computed (batch_processed=true).","messagePattern":"Cannot delete file (.+?)\\. The file is referenced by (.+?) batch\\(es\\) in non-terminal state: (.+?)\\. To delete this file before complete cost tracking, please delete or cancel the referencing batch\\(es\\) first\\. Alternatively, wait for all batches to complete and for cost to be computed \\(batch_processed=true\\)\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"enterprise/litellm_enterprise/proxy/hooks/managed_files.py","lineNumber":1528,"sourceCode":"            )\n\n            # Add specific batch details if not too many\n            if len(referencing_batches) <= MAX_BATCHES_IN_ERROR:\n                error_message += f\": {', '.join(batch_statuses)}. \"\n            else:\n                error_message += f\" (showing {MAX_BATCHES_IN_ERROR} most recent): {', '.join(batch_statuses)}. \"\n\n            error_message += (\n                \"To delete this file before complete cost tracking, please delete or cancel the referencing batch(es) first. \"\n                \"Alternatively, wait for all batches to complete and for cost to be computed (batch_processed=true).\"\n            )\n\n            # Record blocked deletion metric\n            prom_logger = self._get_prometheus_logger()\n            if prom_logger:\n                prom_logger.record_managed_file_deleted(result=\"blocked\")\n\n            raise HTTPException(\n                status_code=400,\n                detail=error_message,\n            )\n\n    async def afile_delete(\n        self,\n        file_id: str,\n        litellm_parent_otel_span: Optional[Span],\n        llm_router: Router,\n        **data: Dict,\n    ) -> OpenAIFileObject:\n\n        # Check if file deletion should be blocked due to batch references\n        await self._check_file_deletion_allowed(file_id)\n\n        # file_id = convert_b64_uid_to_unified_uid(file_id)\n        model_file_id_mapping = await self.get_model_file_id_mapping([file_id], litellm_parent_otel_span)\n","sourceCodeStart":1510,"sourceCodeEnd":1546,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/enterprise/litellm_enterprise/proxy/hooks/managed_files.py#L1510-L1546","documentation":"afile_delete guards batch cost tracking: a managed file cannot be deleted while any batch referencing it is in a non-terminal state, because cost computation still needs the file. The 400 detail lists the referencing batch ids and statuses (capped at MAX_BATCHES_IN_ERROR most recent), a 'blocked' Prometheus metric is recorded, and remediation steps are embedded.","triggerScenarios":"DELETE /v1/files/{file_id} while at least one batch created from that file is in a non-terminal state (in_progress, validating, finalizing, ...) and batch_processed is not true.","commonSituations":"Cleanup crons that delete files right after submitting batches; very long-running batches; the batch cost-tracking job lagging behind batch completion.","solutions":["Cancel or delete the referencing batches first (POST /v1/batches/{batch_id}/cancel or the batch delete endpoint), then retry the file delete","Wait for all referencing batches to reach a terminal state and for cost to be computed (batch_processed=true)","Make cleanup scripts parse the batch ids from this error and skip or defer those files"],"exampleFix":"# before\ncurl -X DELETE http://0.0.0.0:4000/v1/files/{file_id} -H 'Authorization: Bearer sk-1234'  # 400 while batch in_progress\n\n# after\ncurl -X POST http://0.0.0.0:4000/v1/batches/{batch_id}/cancel -H 'Authorization: Bearer sk-1234'\ncurl -X DELETE http://0.0.0.0:4000/v1/files/{file_id} -H 'Authorization: Bearer sk-1234'","handlingStrategy":"validation","validationCode":"batches = await list_batches_for_file(file_id)  # or list all and filter\nnon_terminal = {b.id for b in batches if b.status not in (\"completed\", \"failed\", \"expired\", \"cancelled\")}\nif non_terminal:\n    for bid in non_terminal:\n        await cancel_batch(bid)\n    await wait_until_batches_terminal(non_terminal)\nawait delete_file(file_id)","typeGuard":null,"tryCatchPattern":"try:\n    await proxy.files.delete(file_id)\nexcept HTTPStatusError as e:\n    if e.response.status_code == 400 and \"non-terminal state\" in e.response.text:\n        # parse batch ids from detail, cancel/wait, then retry once\n        ...","preventionTips":["Make file cleanup jobs batch-aware: check batch statuses before deleting","Never delete inputs to in-flight batches in the same pipeline run","Wait for batch_processed=true before end-of-job cleanup"],"tags":["litellm","managed-files","batches","cost-tracking","http-400"],"backgroundTag":"resource-in-use","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}