17 days ago
All new deployments fail healthcheck with "service unavailable" even though the application responds HTTP 200 to /health internally.
Symptoms:
App starts, listens on
0.0.0.0:3000, responds 200 to/health(visible in deploy logs)Railway's healthcheck prober simultaneously reports "service unavailable" for every attempt
Retries exhaust the full window and deploy fails
Deploy logs (truncated):
Starting Healthcheck
Path: /health
Retry window: 1m40s
Attempt #1 failed with service unavailable. Continuing to retry for 1m29s
Attempt #2 failed with service unavailable. Continuing to retry for 1m27s
timestamp=... level=INFO message="Listening on http://0.0.0.0:3000"
timestamp=... message="Sent HTTP response" http.status=200 http.method=GET http.url=/health
timestamp=... message="Sent HTTP response" http.status=200 http.method=GET http.url=/health
Attempt #3 failed with service unavailable. Continuing to retry for 1m25s
Attempt #4 failed with service unavailable. Continuing to retry for 1m21s
...
Deploy failed
What I've tried (all produce the same result):
railway up(CLI upload)railway redeploy(build from GitHub repo)Removing Docker
HEALTHCHECKinstruction from DockerfileRemoving
PORTenv var (let Railway inject it)Setting
PORT=3000explicitlyIncreasing
healthcheckTimeoutto 300s inrailway.tomlDisabling Cloudflare proxy (DNS only)
Removing the auto-generated Railway domain
Deleting the service and creating a brand new one
What works:
Redeploying a previously successful deployment from the dashboard (old cached image)
Setup:
Node.js 24.13.1-alpine, Effect Platform, Prisma ORM
PORT=3000, app listens on0.0.0.0:3000Custom domain with target port 3000
railway.toml: healthcheckPath = "/health", healthcheckTimeout = 300
This looks identical to the issue in this thread which was caused by conflicting firewall rules and required a platform-side fix.
2 Replies
17 days ago
Found the issue, my CORS middleware was crashing on requests with no Origin header. When you use a specific allowlist (not *), the origin matcher function receives undefined for same-origin or server-to-server requests and throws. Adding a null check before matching fixed it.
17 days ago
Glad you found it. CORS origin matchers receiving undefined for requests without an Origin header (like our healthcheck prober) is a subtle one. Thanks for sharing the fix.
Status changed to Awaiting User Response Railway • 17 days ago
Status changed to Solved brody • 17 days ago
