Skip to main content
An HTTP error on an application’s domain comes from one of three places: your application, Sevalla (IP restrictions, maintenance mode, hibernation, or the ingress that routes requests to the web process), or Cloudflare when it can’t get a valid response. The status code and the page’s body tell them apart. This page lists the errors Sevalla and Cloudflare return, what each means on Sevalla, and the fix.

Who returned the error

The access logs record the status of every request, and the Status codes chart on the Analytics tab shows when errors started.

403 Forbidden

Symptom. Requests return 403. Cause.
  • A plain body Forbidden means the application’s IP restrictions blocked the visitor’s address. With an allowlist, every address not on it is blocked; with a denylist, the listed ones.
  • Any other 403 comes from your code or your web server: it can’t read the files (file permissions), or an .htaccess rule (Deny, RewriteRule, FilesMatch) or a document root that points at the wrong folder refuses the request.
Fix.
  • For IP restrictions, check the IP restrictions section on the Networking tab and add or remove the address. Find your own address with a site such as https://ifconfig.me.
  • For file permissions, make files readable (644) and folders traversable (755) in your build.
  • For the server configuration, fix the rule or the document root. With Buildpacks and Apache, the application is in /workspace, so point the document root at its public folder, for example heroku-php-apache2 public/.

404 Not Found

Symptom. Every path of a domain returns 404, including /. Cause. The request doesn’t reach the web process: HTTP traffic is turned off, the domain isn’t active yet, or the application has no successful deployment. Fix. Check that Expose HTTP traffic on the Networking tab shows the domain as enabled, that the domain is Active on the Domains tab (see Troubleshoot custom domains), and that the latest deployment succeeded. A 404 on some paths only comes from your application’s routes.

500 Internal Server Error

Symptom. Requests return 500, usually with your framework’s error page. Cause. An unhandled error in your application while it answered the request. Common causes are a missing or wrong environment variable and a database the application can’t reach. Fix. Find the stack trace in the runtime logs at the time of the request: pick the Error level and the web process. For database errors, see The application cannot connect to a database.

502 Bad Gateway and upstream connect error

Symptom. Requests return 502, or a page with:
Cause. Sevalla reached the web process’s instance but nothing accepted the connection on the web process port. The server listens on another port, listens only on localhost, isn’t listening yet, or crashed while answering. Fix.
  1. Make the server listen on 0.0.0.0 and on the PORT environment variable, or set the Port on the Networking tab to the port your server uses.
  2. Check the runtime logs for crashes during requests.
  3. Add a readiness probe so that instances get traffic only once they listen.

503 Service Unavailable

504 Gateway Timeout and Cloudflare error 524

Symptom. Long requests fail with 504 Gateway Timeout, or Cloudflare’s Error 524: A timeout occurred. Cause. Cloudflare waits up to 185 seconds for your application to start answering a request. A slow query, an external API that hangs, or a long task inside the request exceeds it. Fix. Find the slow requests in Slowest requests on the Analytics tab and make them faster: add database indexes, cache results, call external services with timeouts. Move work that takes minutes to a background worker and return a response right away. If the process is at its CPU or memory limit, give it a larger size or more instances.

Cloudflare errors 520, 521 and 522

These Cloudflare pages mean Cloudflare got no valid response from Sevalla:

Too many redirects

Symptom. The browser stops with ERR_TOO_MANY_REDIRECTS, or the page redirects to itself. Cause. The application forces HTTPS by looking at the connection it receives, which isn’t HTTPS, so it redirects every request, including the ones that already used HTTPS. Sevalla already redirects HTTP to HTTPS for every domain. Fix. Make your framework trust the proxy headers so it sees X-Forwarded-Proto: https, for example app.set("trust proxy", true) in Express or the TrustProxies middleware in Laravel, or remove the application’s own HTTP-to-HTTPS redirect. See Request headers. A redirect loop on a custom domain can also come from your DNS provider’s own proxy settings; see Troubleshoot custom domains. If you can’t find the cause, contact support with the URL, the time and, for Cloudflare errors, the Ray ID.