{"record":{"id":"83035c92a4b05ae0","repo":"zylon-ai/private-gpt","slug":"file-not-found-file-data","errorCode":null,"errorMessage":"File not found: {file_data}","messagePattern":"File not found: (.+?)","errorType":"exception","errorClass":"FileNotFoundError","httpStatus":500,"severity":"error","filePath":"private_gpt/components/ingest/utils.py","lineNumber":378,"sourceCode":"    file_metadata: dict[str, Any] | None,\n) -> str | None:\n    # Extracting the file name to help detect the file type through the extension\n    file_name: str | None = (\n        file_metadata.get(MetadataKeys.FILENAME.value) if file_metadata else None\n    )\n    # In case the file name does not contain an extension, we discard it\n    if file_name and len(Path(file_name).suffix) == 0:\n        file_name = None\n\n    return file_name\n\n\ndef get_file_info(\n    file_data: Path, file_name: str | None, progress: NotifyProtocol | None = None\n) -> FileInfo:\n    \"\"\"Function to extract file information.\"\"\"\n    if not exist_file(file_data):\n        raise FileNotFoundError(f\"File not found: {file_data}\")\n\n    steps = 7\n    current_step = 0\n\n    def notify() -> None:\n        if progress is None:\n            return\n        nonlocal current_step\n        current_step += 1\n        if current_step <= steps:\n            progress(percentage=current_step * 100 // steps)\n\n    file_name = file_name\n    extension = get_extension(file_name) if file_name else None\n    notify()\n\n    file_size = get_filesize(file_data)\n    notify()","sourceCodeStart":360,"sourceCodeEnd":396,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/components/ingest/utils.py#L360-L396","documentation":"FileNotFoundError raised by get_file_info when the Path passed to ingestion does not exist on disk (exist_file check fails). This happens before any file metadata is gathered — the file was never there, was deleted, or the path is wrong.","triggerScenarios":"Calling get_file_info (directly or via the validate/ingest pipeline) with a Path that does not exist: wrong path string, file already cleaned up by a temp-dir reaper, or a worker on a different host without the shared volume.","commonSituations":"Multi-node deployments where the API server saves the upload locally but the Celery worker cannot see that path; temp file deleted before async processing starts; path traversal/normalization bugs producing nonexistent paths.","solutions":["Verify the path exists on the machine actually executing ingestion (worker node), not just the API node.","Share uploads via a common volume or object storage across API and workers.","Check that nothing (cron cleanup, tmp reaper) deletes staged files between upload and parse.","Log the resolved absolute path right before ingest to catch normalization bugs."],"exampleFix":"// before\nnodes = parser.file_to_nodes(file_info)  # path may be stale\n\n// after\nfrom pathlib import Path\nif not file_info.file_data.exists():\n    raise FileNotFoundError(f\"staged file vanished: {file_info.file_data}\")\nnodes = parser.file_to_nodes(file_info)","handlingStrategy":"validation","validationCode":"from pathlib import Path\np = Path(file_path).resolve()\nif not p.is_file():\n    raise FileNotFoundError(f'ingest input missing on this host: {p}')","typeGuard":null,"tryCatchPattern":"try:\n    file_info = get_file_info(path, file_name=name)\nexcept FileNotFoundError as e:\n    logger.error('staged file vanished or wrong volume: %s', e)\n    retry_with_fresh_upload()","preventionTips":["In distributed setups, stage uploads on shared storage (volume or S3), never node-local temp dirs.","Verify the file exists on the exact host executing the Celery task, not just the API node."],"tags":["ingestion","file-not-found","filesystem","distributed-systems"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}