{"record":{"id":"9e63bf7533844b35","repo":"infiniflow/ragflow","slug":"failed-to-fetch-email-ids-status","errorCode":null,"errorMessage":"Failed to fetch email ids; {status=}","messagePattern":"Failed to fetch email ids; (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"common/data_source/imap_connector.py","lineNumber":450,"sourceCode":"    mailbox: str,\n    start: SecondsSinceUnixEpoch,\n    end: SecondsSinceUnixEpoch,\n) -> list[str]:\n    if not _select_mailbox(mail_client, mailbox):\n        logging.warning(f\"Skip mailbox: {mailbox}\")\n        return []\n\n    start_dt = datetime.fromtimestamp(start, tz=timezone.utc)\n    end_dt = datetime.fromtimestamp(end, tz=timezone.utc) + timedelta(days=1)\n\n    start_str = start_dt.strftime(\"%d-%b-%Y\")\n    end_str = end_dt.strftime(\"%d-%b-%Y\")\n    search_criteria = f'(SINCE \"{start_str}\" BEFORE \"{end_str}\")'\n\n    status, email_ids_byte_array = mail_client.search(None, search_criteria)\n\n    if status != _IMAP_OKAY_STATUS or not email_ids_byte_array:\n        raise RuntimeError(f\"Failed to fetch email ids; {status=}\")\n\n    email_ids: bytes = email_ids_byte_array[0]\n\n    return [email_id.decode() for email_id in email_ids.split()]\n\n\ndef _fetch_email(mail_client: imaplib.IMAP4_SSL, email_id: str) -> Message | None:\n    status, msg_data = mail_client.fetch(message_set=email_id, message_parts=\"(RFC822)\")\n    if status != _IMAP_OKAY_STATUS or not msg_data:\n        return None\n\n    data = msg_data[0]\n    if not isinstance(data, tuple):\n        raise RuntimeError(f\"Message data should be a tuple; instead got a {type(data)=} {data=}\")\n\n    _, raw_email = data\n    return email.message_from_bytes(raw_email)\n","sourceCodeStart":432,"sourceCodeEnd":468,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/common/data_source/imap_connector.py#L432-L468","documentation":"Raised by _fetch_email_ids_in_mailbox when mail_client.search returns a non-OK status or an empty response list. The date-window search (SINCE/BEFORE built from the start/end epoch args) failed at the protocol level. Note that an empty-but-OK search (no mail in range) returns normally - this error means the command itself failed.","triggerScenarios":"Session dropped or mailbox deselected before SEARCH; the server rejects the search criteria format; server under load returning 'NO'. Triggered per-mailbox during checkpoint processing when message ids need to be enumerated.","commonSituations":"Intermittent disconnects on long syncs; servers rejecting the quoted date format due to locale differences; two jobs sharing one IMAP connection concurrently; the mailbox being deleted or renamed between LIST and SEARCH.","solutions":["Retry with a freshly created mail client (re-login) and re-select the mailbox before searching.","Verify the mailbox still exists immediately before searching if folders change frequently.","Serialize access so only one operation uses an IMAP connection at a time.","Reproduce the SEARCH manually to see the server's response text if failures are persistent."],"exampleFix":"# before\nids = _fetch_email_ids_in_mailbox(client, mailbox, start, end)  # RuntimeError mid-sync\n\n# after\ntry:\n    ids = _fetch_email_ids_in_mailbox(client, mailbox, start, end)\nexcept RuntimeError:\n    client = connector._get_mail_client()\n    client.select(mailbox, readonly=True)\n    ids = _fetch_email_ids_in_mailbox(client, mailbox, start, end)","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    ids = _fetch_email_ids_in_mailbox(client, mailbox, start, end)\nexcept RuntimeError as e:\n    if 'Failed to fetch email ids' not in str(e):\n        raise\n    client = connector._get_mail_client()\n    client.select(mailbox, readonly=True)\n    ids = _fetch_email_ids_in_mailbox(client, mailbox, start, end)","preventionTips":["Re-select the mailbox after any reconnect before issuing SEARCH.","Run one operation per IMAP connection at a time; sessions are not concurrency-safe.","Bound retries with backoff so a persistent server failure surfaces instead of looping."],"tags":["imap","email","network","retry"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}