{"record":{"id":"8f3fbfc6b0c6421d","repo":"OpenBMB/ChatDev","slug":"attachment-attachment-id-not-found","errorCode":null,"errorMessage":"Attachment '{attachment_id}' not found","messagePattern":"Attachment '(.+?)' not found","errorType":"exception","errorClass":"KeyError","httpStatus":null,"severity":"error","filePath":"utils/attachments.py","lineNumber":217,"sourceCode":"            size=size,\n            remote_file_id=remote_file_id,\n        )\n        record = AttachmentRecord(ref=ref, kind=kind, description=description, extra=extra or {})\n        self._records[attachment_id] = record\n        if persist:\n            self._persistent_ids.add(attachment_id)\n            self._save_manifest()\n        else:\n            self._persistent_ids.discard(attachment_id)\n        if ref.sha256:\n            self._hash_index[ref.sha256] = attachment_id\n        return record\n\n    def update_remote_file_id(self, attachment_id: str, remote_file_id: str) -> None:\n        \"\"\"Attach a provider file_id to an existing record (after upload).\"\"\"\n        record = self._records.get(attachment_id)\n        if not record:\n            raise KeyError(f\"Attachment '{attachment_id}' not found\")\n        record.ref.remote_file_id = remote_file_id\n        if attachment_id in self._persistent_ids:\n            self._save_manifest()\n\n    def get(self, attachment_id: str) -> AttachmentRecord | None:\n        return self._records.get(attachment_id)\n\n    def to_message_block(self, attachment_id: str) -> MessageBlock:\n        record = self._records.get(attachment_id)\n        if not record:\n            raise KeyError(f\"Attachment '{attachment_id}' not found\")\n        return record.as_message_block()\n\n    def list_records(self) -> Dict[str, AttachmentRecord]:\n        return dict(self._records)\n\n    def export_manifest(self) -> Dict[str, Any]:\n        return {","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/OpenBMB/ChatDev/blob/4fb2db0ea90375ce1059f44fe03ffbd191a7a169/utils/attachments.py#L199-L235","documentation":"AttachmentManager.update_remote_file_id raises KeyError when the attachment_id is not in the in-memory _records registry. It is called after uploading to a provider to store the returned remote file id, so the record must have been registered earlier in the same manager instance.","triggerScenarios":"Calling update_remote_file_id after a server restart (records are in-memory), with a typo'd id, or before register_file/register_bytes created the record.","commonSituations":"State lost across process restarts or between manager instances; multi-worker deployment where registration and update hit different workers; race where the record is evicted before the upload completes.","solutions":["Confirm the registration call (register_file/register_bytes) succeeded and use the id it returned","Use the same AttachmentManager instance for register and update","Catch KeyError and re-register/re-upload the attachment to get a fresh id"],"exampleFix":"# before\nmanager.update_remote_file_id(att_id, remote_id)\n# after\nif manager.get(att_id) is None:\n    raise UnknownAttachment(att_id)\nmanager.update_remote_file_id(att_id, remote_id)","handlingStrategy":"validation","validationCode":"if manager.get(attachment_id) is None:\n    raise UnknownAttachment(attachment_id)","typeGuard":"def has_attachment(m, aid: str) -> bool:\n    return m.get(aid) is not None","tryCatchPattern":"try:\n    manager.update_remote_file_id(aid, rid)\nexcept KeyError:\n    rec = re_register_source(); manager.update_remote_file_id(rec.attachment_id, rid)","preventionTips":["Use get() (None-returning) for lookups","Keep register+update on the same manager instance/process","Reload persisted manifest before cross-process updates"],"tags":["attachments","key-error","state"],"backgroundTag":"missing-record-id","analyzedSha":"4fb2db0ea90375ce1059f44fe03ffbd191a7a169","analyzedAt":"2026-08-27T14:35:29.622Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}