{"record":{"id":"239b7b60c24ef13b","repo":"phacility/phabricator","slug":"err-duplicate","errorCode":"err:duplicate","errorMessage":"Ignoring email with \"Message-ID\" hash \"%s\" that has been seen %d times, including this message.","messagePattern":"Ignoring email with \"Message-ID\" hash \"(.+?)\" that has been seen (.+?) times, including this message\\.","errorType":"exception","errorClass":"PhabricatorMetaMTAReceivedMailProcessingException","httpStatus":null,"severity":"info","filePath":"src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php","lineNumber":411,"sourceCode":"      return;\n    }\n\n    $first_message = reset($messages);\n    if ($first_message->getID() == $this->getID()) {\n      // If this is the first copy of the message, it is okay to process it.\n      // We may not have been able to to process it immediately when we received\n      // it, and could may have received several copies without processing any\n      // yet.\n      return;\n    }\n\n    $message = pht(\n      'Ignoring email with \"Message-ID\" hash \"%s\" that has been seen %d '.\n      'times, including this message.',\n      $message_id_hash,\n      $messages_count);\n\n    throw new PhabricatorMetaMTAReceivedMailProcessingException(\n      MetaMTAReceivedMailStatus::STATUS_DUPLICATE,\n      $message);\n  }\n\n  private function dropEmptyMail() {\n    $body = $this->getCleanTextBody();\n    $attachments = $this->getAttachments();\n\n    if (strlen($body) || $attachments) {\n      return;\n    }\n\n    // Only send an error email if the user is talking to just Phabricator.\n    // We can assume if there is only one \"To\" address it is a Phabricator\n    // address since this code is running and everything.\n    $is_direct_mail = (count($this->getToAddresses()) == 1) &&\n                      (count($this->getCCAddresses()) == 0);\n","sourceCodeStart":393,"sourceCodeEnd":429,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php#L393-L429","documentation":"dropMailAlreadyReceived() drops inbound mail whose normalized 'Message-ID' hash has already been recorded (STATUS_DUPLICATE): the code counts prior received mails with the same getMessageIDHash() and throws once this copy is not the first. Duplicate suppression is what makes Reply-All and multi-copy delivery safe — the same message hitting several inbound addresses is processed once. Duplicate status is also excluded from bounce emails.","triggerScenarios":"Processing a received mail whose Message-ID hash already appears in the received-mail table with a processed ancestor. Happens when the MTA delivers one message to multiple Phabricator addresses (To: D123+...@ and CC: bugs@), when a user forwards/re-sends a message keeping the same Message-ID, or when a queue redelivers after a crash.","commonSituations":"Reply-all to a thread with two Phabricator addresses (expected and harmless — first receiver wins); mail server retry delivering the same message; users dragging the same message into a mail-to-ticket address twice; monitoring that resubmits mail with a stable Message-ID.","solutions":["Treat STATUS_DUPLICATE as benign in most cases — check MetaMTA > Received Mail and confirm the first copy was processed successfully.","If you need a genuine second submission, send a fresh message (new Message-ID) rather than resending/forwarding the identical one.","If a whole queue got marked duplicate after a crash, inspect whether the FIRST copy was processed; if not, requeue that original.","Admins: verify inbound routing does not fan one message out to multiple Phabricator receive addresses if per-copy processing matters."],"exampleFix":"// before: same Message-ID delivered to two Phabricator addresses\n// copy 1 -> processed; copy 2 -> err:duplicate, dropped\n\n// after (if both actions are truly wanted): send two separate messages\n// each with its own Message-ID, addressed to the intended object","handlingStrategy":"try-catch","validationCode":"// Before submitting, check the Message-ID has not been seen (mirrors dropMailAlreadyReceived):\n$hash = PhabricatorMetaMTAReceivedMail::hashMessageID($message_id);\n$seen = id(new PhabricatorMetaMTAReceivedMailQuery())\n  ->setViewer($viewer)\n  ->withMessageIDHashes(array($hash))\n  ->execute();\nif ($seen) { /* already ingested once: skip */ }","typeGuard":null,"tryCatchPattern":"try {\n  $received_mail->processIncomingMail($sender);\n} catch (PhabricatorMetaMTAReceivedMailProcessingException $ex) {\n  if ($ex->getStatusCode() === MetaMTAReceivedMailStatus::STATUS_DUPLICATE) {\n    // verify the FIRST copy succeeded, then treat as done — never blind-retry\n    return;\n  }\n  throw $ex;\n}","preventionTips":["Submit each new action as a fresh message with its own Message-ID; never resend identical mail.","Route one inbound address per message; avoid fan-out deliveries of a single Message-ID to several Phabricator handlers.","Treat duplicate status as idempotency working, and verify the first copy's outcome instead of retrying."],"tags":["metamta","email","idempotency","duplicate-detection","inbound-mail"],"backgroundTag":"duplicate-message-id","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}