{"record":{"id":"488419ae346291f2","repo":"sj26/mailcatcher","slug":"error-receiving-message","errorCode":null,"errorMessage":"Error receiving message","messagePattern":"Error receiving message","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/mail_catcher/smtp.rb","lineNumber":63,"sourceCode":"  end\n\n  def receive_data_chunk(lines)\n    current_message[:source] ||= +\"\"\n\n    lines.each do |line|\n      current_message[:source] << line << \"\\r\\n\"\n    end\n\n    true\n  end\n\n  def receive_message\n    MailCatcher::Mail.add_message current_message\n    MailCatcher::Mail.delete_older_messages!\n    puts \"==> SMTP: Received message from '#{current_message[:sender]}' (#{current_message[:source].length} bytes)\"\n    true\n  rescue => exception\n    MailCatcher.log_exception(\"Error receiving message\", @current_message, exception)\n    false\n  ensure\n    @current_message = nil\n  end\nend\n","sourceCodeStart":45,"sourceCodeEnd":69,"githubUrl":"https://github.com/sj26/mailcatcher/blob/18a9cb7a79b321b2bcb51608dd793ea51255189e/lib/mail_catcher/smtp.rb#L45-L69","documentation":"The SMTP server's receive_message (smtp.rb:57-67) finished the DATA phase and tried to store the message via MailCatcher::Mail.add_message and prune old messages; something in that path raised, the rescue caught it, logged this report with the half-built @current_message as context, and returned false — which makes the EventMachine SMTP server report a delivery error to the sending client. The message is lost from MailCatcher's UI, but the process stays up.","triggerScenarios":"A SMTP client completes MAIL FROM/RCPT TO/DATA for a message whose source then fails to parse (Mail.new in mail.rb:47 raising on malformed MIME/encoding) or fails to persist (SQLite3 insert errors in mail.rb:45-67, e.g. null bytes in the source with newer sqlite3 gems, or a prepared-statement type mismatch). Also fires if delete_older_messages! raises while honoring --messages-limit.","commonSituations":"ActionMailer/Rails apps sending 8-bit or malformed headers; upgrading the sqlite3 gem (1.3 -> 1.4+) under an old mailcatcher, producing ArgumentError/SQLite3 errors on insert; unusual attachments (embedded null bytes, odd charsets); automated test suites that send hand-rolled raw SMTP payloads.","solutions":["Run `mailcatcher --foreground --verbose` and send one failing message; read the `Exception:` line of the printed block to identify the real error.","If it is sqlite3-related (null byte / argument errors), pin a compatible sqlite3 (`gem install sqlite3 -v 1.3.13`) or upgrade mailcatcher to the latest release whose gem constraints are compatible.","If it is Mail/MIME parsing, capture the failing source (context line shows sender/recipients; re-send the same mail to a file with a catch-all like `nc -l 1025`) and fix the sending side's encoding/headers.","If you use --messages-limit, try disabling it to rule out delete_older_messages! as the raiser.","If it reproduces on the latest version with a valid email, file an issue with the full block."],"exampleFix":"# before\nmailcatcher   # daemonized; failures vanish after \"Error receiving message\"\n\n# after: visible triage + compatible sqlite3\nmailcatcher --foreground --verbose\ngem uninstall sqlite3\ngem install sqlite3 -v 1.3.13   # or: gem update mailcatcher","handlingStrategy":"try-catch","validationCode":"# Sanity-check a message before handing the SMTP path a pathological payload\n# (guards the two known raisers: SQLite3 insert and Mail MIME parsing)\ndef safe_to_send?(raw_source)\n  raw_source.is_a?(String) &&\n    !raw_source.include?(\"\\0\") && # null bytes break older sqlite3 inserts\n    raw_source.valid_encoding? &&\n    raw_source.each_line.none? { |l| l.bytesize > 998 } rescue false\nend\n\nabort \"refusing to send malformed mail\" unless safe_to_send?(mail_source)","typeGuard":"# Narrow to the hash shape receive_message expects before injecting into MailCatcher::Mail\ndef valid_message_hash?(msg)\n  msg.is_a?(Hash) && msg.key?(:sender) && msg[:sender].is_a?(String) &&\n    msg[:recipients].is_a?(Array) && msg[:source].is_a?(String) && !msg[:source].empty?\nend","tryCatchPattern":"# receive_message already rescues and returns false; embedders should mirror that contract\nbegin\n  MailCatcher::Mail.add_message(current_message)\nrescue => e\n  MailCatcher.log_exception(\"Error receiving message\", current_message, e)\n  false # SMTP-equivalent: tell the client this delivery failed, keep serving\nend","preventionTips":["Pin sqlite3 to the version your mailcatcher release was built against (classic break: sqlite3 1.4 under old mailcatcher).","Send mail with correct MIME/charset headers from apps; avoid hand-rolled SMTP payloads in tests.","Run MailCatcher in the foreground during test suites so receive-time reports are visible immediately.","Archive raw sources of failed sends (trap them in your own rescue) so lost messages are reproducible."],"tags":["smtp","sqlite","mail-parsing","eventmachine","data-loss"],"backgroundTag":"database-insert-failed","analyzedSha":"18a9cb7a79b321b2bcb51608dd793ea51255189e","analyzedAt":"2026-08-21T18:56:10.605Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}