sj26/mailcatcher · error
Exception: #{exception}
Error message
Exception: #{exception} What it means
The second line of MailCatcher's log_exception report (lib/mail_catcher.rb:62): it prints the caught exception via string interpolation (`#{}=> exception.to_s`), giving `Class: message` — e.g. `SQLite3::SQLException: ...` or `Errno::EPIPE: Broken pipe`. This line is the actual diagnosis; the surrounding lines are context and backtrace.
Source
Thrown at lib/mail_catcher.rb:62
def browsable?
windows? or which? "open"
end
def browse url
if windows?
system "start", "/b", url
elsif which? "open"
system "open", url
end
end
def log_exception(message, context, exception)
gems_paths = (Gem.path | [Gem.default_dir]).map { |path| Regexp.escape(path) }
gems_regexp = %r{(?:#{gems_paths.join("|")})/gems/([^/]+)-([\w.]+)/(.*)}
gems_replace = '\1 (\2) \3'
puts "*** #{message}: #{context.inspect}"
puts " Exception: #{exception}"
puts " Backtrace:", *exception.backtrace.map { |line| " #{line.sub(gems_regexp, gems_replace)}" }
puts " Please submit this as an issue at https://github.com/sj26/mailcatcher/issues"
end
@@defaults = {
:smtp_ip => "127.0.0.1",
:smtp_port => "1025",
:http_ip => "127.0.0.1",
:http_port => "1080",
:http_path => "/",
:messages_limit => nil,
:verbose => false,
:daemon => !windows?,
:browse => false,
:quit => true,
}
def optionsView on GitHub (pinned to 18a9cb7a79)
Solutions
- Identify the exception class on this line and resolve by that class: SQLite3::* -> fix gem pairing; IOError/EPIPE -> transient client disconnect, safe to ignore; NoMethodError/ArgumentError in mail parsing -> inspect the message source from the context line.
- Run `mailcatcher -f -v` so the report prints to your terminal instead of being swallowed by daemon mode.
- Search the exact exception string in https://github.com/sj26/mailcatcher/issues — recurring classes (sqlite3 null-byte, encoding) have known fixes.
- If unclassifiable, capture the whole block (context + exception + backtrace) and file an issue.
Defensive patterns
Strategy: try-catch
Try / catch
# Classify by the exception the report prints, then decide
begin
MailCatcher::Mail.add_message(msg)
rescue SQLite3::Exception => e
abort "incompatible sqlite3 for mailcatcher: #{e.message} — pin sqlite3 ~> 1.3"
rescue StandardError => e
warn "unclassified: #{e.class}: #{e.message}" # corresponds to the printed 'Exception:' line
end Prevention
- Grep daemon logs for 'Exception:' lines after gem updates instead of relying on SMTP client symptoms.
- Keep a pinned set of gem versions for the mailcatcher bundle; record what changed when reports appear.
- Distinguish disconnect classes (EPIPE/IOError -> ignore) from storage/parse classes (act) before debugging.
When it happens
Trigger: Any exception swallowed by the two internal rescues: smtp.rb:62 catching failures while storing a message (SQLite3 insert errors, Mail MIME parse raising), and application.rb:89 catching failures of Faye ws.send to a dead browser connection (IOError, EPIPE). What appears here is whatever those rescues caught.
Common situations: Triaging a `451`/delivery failure reported by an SMTP client and matching it to this line; sqlite3 gem major-version incompatibility raising on message insert; browsers disconnecting (tab close, sleep) while the Bus broadcasts a new message; Ruby upgrades changing encoding behavior on binary mail parts.
Related errors
- *** #{message}: #{context.inspect}
- Backtrace:
- Please submit this as an issue at https://github.com/sj2
AI-assisted analysis of sj26/mailcatcher@18a9cb7a79 (2026-08-21).
Data as JSON: /api/errors/64fd0294943f7344.
Report an issue: GitHub.