{"record":{"id":"e120bfbe37ea6cf9","repo":"OpenBMB/ChatDev","slug":"attachment-source-not-found-source","errorCode":null,"errorMessage":"Attachment source not found: {source}","messagePattern":"Attachment source not found: (.+?)","errorType":"exception","errorClass":"FileNotFoundError","httpStatus":null,"severity":"error","filePath":"utils/attachments.py","lineNumber":89,"sourceCode":"\n    def register_file(\n        self,\n        file_path: Path | str,\n        *,\n        kind: MessageBlockType = MessageBlockType.FILE,\n        display_name: Optional[str] = None,\n        mime_type: Optional[str] = None,\n        attachment_id: Optional[str] = None,\n        copy_file: bool = True,\n        description: Optional[str] = None,\n        extra: Optional[Dict[str, Any]] = None,\n        persist: bool = True,\n        deduplicate: bool = False,\n    ) -> AttachmentRecord:\n        \"\"\"Register a local file and return its attachment record.\"\"\"\n        source = Path(file_path)\n        if not source.exists():\n            raise FileNotFoundError(f\"Attachment source not found: {source}\")\n\n        guessed_mime = mime_type or (mimetypes.guess_type(source.name)[0] or \"application/octet-stream\")\n        attachment_id = attachment_id or uuid.uuid4().hex\n        sha256_source = _sha256_file(source)\n\n        if deduplicate:\n            existing = self._find_duplicate_by_hash(\n                sha256_source,\n                copy_file=copy_file,\n                source_path=source,\n            )\n            if existing:\n                return existing\n        if copy_file:\n            target_dir = self.root / attachment_id\n            target_dir.mkdir(parents=True, exist_ok=True)\n            target_path = target_dir / source.name\n            shutil.copy2(source, target_path)","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/OpenBMB/ChatDev/blob/4fb2db0ea90375ce1059f44fe03ffbd191a7a169/utils/attachments.py#L71-L107","documentation":"AttachmentManager.register_file raises plain FileNotFoundError when the local path passed in does not exist on disk — checked before any MIME guessing, hashing, or persistence. It is a pre-registration sanity check, not a download failure.","triggerScenarios":"Calling register_file (directly or via load_file/save_upload_file/_persist_single_attachment/report_export_pdf) with a path whose file was moved, deleted, or never written; relative path resolved against an unexpected CWD; typo in the path.","commonSituations":"Temp file cleaned up before registration; path built from user input that was never validated; running the process from a different working directory so relative paths break; race where an upstream step failed to produce the file.","solutions":["Verify the path exists (and is absolute) before calling register_file","Check the upstream producer of the file actually wrote it (earlier step may have failed silently)","Use Path(...).resolve() to normalize relative paths against an explicit base"],"exampleFix":"# before\nrec = manager.register_file(p)\n# after\np = Path(p).resolve()\nif not p.is_file():\n    raise FileNotFoundError(f\"expected export at {p}\")\nrec = manager.register_file(p)","handlingStrategy":"type-guard","validationCode":"p = Path(file_path).resolve()\nif not p.is_file():\n    raise FileNotFoundError(f'missing attachment source: {p}')","typeGuard":"def is_registerable_file(p: str | Path) -> bool:\n    return Path(p).is_file()","tryCatchPattern":"try:\n    rec = manager.register_file(p)\nexcept FileNotFoundError:\n    p = re_generate_export(); rec = manager.register_file(p)","preventionTips":["Resolve paths to absolute before registration","Verify upstream file-producing steps succeeded","Use manager.get() style None-checks before file ops"],"tags":["attachments","filesystem","not-found"],"backgroundTag":"file-not-found","analyzedSha":"4fb2db0ea90375ce1059f44fe03ffbd191a7a169","analyzedAt":"2026-08-27T14:35:29.622Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}