sj26/mailcatcher · error
~~> ERROR: Something's using port #{port}. Are you already r
Error message
~~> ERROR: Something's using port #{port}. Are you already running MailCatcher? What it means
MailCatcher failed to bind one of its two listeners (SMTP on 1025 or HTTP on 1080 by default) because the port is already taken. EventMachine raises only a bare RuntimeError with the text 'no acceptor', which rescue_port pattern-matches at lib/mail_catcher.rb:243, prints this message, and exits the process with status -1. Despite the wording, anything occupying the port triggers it, not just another MailCatcher instance.
Source
Thrown at lib/mail_catcher.rb:244
protected
def smtp_url
"smtp://#{@@options[:smtp_ip]}:#{@@options[:smtp_port]}"
end
def http_url
"http://#{@@options[:http_ip]}:#{@@options[:http_port]}#{@@options[:http_path]}".chomp("/")
end
def rescue_port port
begin
yield
# XXX: EventMachine only spits out RuntimeError with a string description
rescue RuntimeError
if $!.to_s =~ /\bno acceptor\b/
puts "~~> ERROR: Something's using port #{port}. Are you already running MailCatcher?"
puts "==> #{smtp_url}"
puts "==> #{http_url}"
exit -1
else
raise
end
end
end
end
View on GitHub (pinned to 18a9cb7a79)
Solutions
- Find and stop the existing process: `lsof -i :1025 -i :1080` (or `ss -ltnp | grep -E '1025|1080'`), then kill the listed PID — or quit the old MailCatcher via DELETE http://127.0.0.1:1080/ from its web UI.
- If the occupier is another MailCatcher you want gone: `pkill -f mailcatcher` or kill the daemon PID.
- Run on different ports: `mailcatcher --smtp-port 1026 --http-port 1081`, and point your app's SMTP delivery at the new port.
- If you actually need two instances, give each its own --ip/--smtp-port/--http-port combination.
Example fix
# before mailcatcher # ~~> ERROR: Something's using port 1080. Are you already running MailCatcher? # after (option 1: free the port) lsof -ti :1025 -ti :1080 | xargs kill mailcatcher # after (option 2: pick free ports) mailcatcher --smtp-port 1026 --http-port 1081 # then configure the app's SMTP client for localhost:1026
Defensive patterns
Strategy: validation
Validate before calling
# Ruby: verify MailCatcher's ports are free before spawning it
require "socket"
def port_free?(ip, port)
sock = TCPServer.new(ip, port)
true
rescue Errno::EADDRINUSE, Errno::EACCES
false
ensure
sock&.close
end
smtp_port, http_port = 1025, 1080
unless port_free?("127.0.0.1", smtp_port) && port_free?("127.0.0.1", http_port)
abort "port busy: pick others, e.g. mailcatcher --smtp-port #{smtp_port + 1} --http-port #{http_port + 1}"
end
# shell alternative: lsof -i :1025 -i :1080 Prevention
- Remember MailCatcher daemonizes by default on Unix — run it with --foreground in scripts so its lifetime is explicit.
- In CI/docker, always pass explicit --smtp-port/--http-port per job/container to avoid collisions.
- Quit instances through the web UI (DELETE /) or by killing the PID instead of leaving daemons behind.
- When embedding MailCatcher via MailCatcher.run!, preflight-bind the chosen ports yourself before starting the reactor.
When it happens
Trigger: Starting `mailcatcher` when a previous daemonized instance is still running; another app bound to 1025/1080 (e.g. a dev SMTP server, nginx, or another Rails app's mailcatcher); starting MailCatcher twice in CI or docker-compose without unique ports; passing --smtp-port/--http-port (or --ip) values that collide with an existing listener, since both servers are started inside the single EventMachine.run loop (lib/mail_catcher.rb:182,189).
Common situations: MailCatcher daemonizes by default on non-Windows (:daemon => !windows?), so a forgotten background process silently holds the ports; two developers sharing a machine/VM; Docker containers with mirrored host ports; a crashed run whose socket lingers; ports below 1024 chosen without root.
Related errors
AI-assisted analysis of sj26/mailcatcher@18a9cb7a79 (2026-08-21).
Data as JSON: /api/errors/e43e09d5448c9a9c.
Report an issue: GitHub.