I have a site whose .htaccess file contains:

ErrorDocument 404 /errors/404.html
ErrorDocument 500 /errors/500.html

The 404 redirect works just fine, but when I encounter a 500 Internal Server Error, it gives the default Internal Server Error message as opposed to /errors/500.html. It also says

Additionally, a 500 Internal Server Error error was encountered while trying to use an ErrorDocument to handle the request.

More info: I can get it to throw 500 if I type a trailing slash on a .html page that has had the ".html" removed by the remaining part of the htaccess file (e.g. if I try to navigate to http://example.com/test/ where test is actually test.html, then I get an internal server error):

#example.com/page will display the contents of example.com/page.html
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.+)$ $1.html [L,QSA]

#302 from example.com/page.html to example.com/page
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*\.html\ HTTP/
RewriteRule ^(.*)\.html$ /$1 [R=302,L]
  • just a guess: file permissions of the error files differ; or the ".html"-rewrite rule is conflicting with a "real" site you have that has the URL-key 500 Commented Oct 5, 2015 at 20:10
  • Two questions: 1. Can you visit the 500.html page manually? This will show its its a permission error. 2. How are you simulating the 500 error? I've no idea what you mean by yours last sentence "I can get it to throw 500 if I type a trailing slash...etc. especially since you then give examples with no trailing slashes. Commented Oct 6, 2015 at 22:06
  • @BazzaDP I can visit the 500.html page manually. Woops, I'll update the example to have a trailing slash. So if example.com/test/ is tried, a trailing slash is on the end of what is actually a html file
    – binaryfunt
    Commented Oct 7, 2015 at 20:28
  • You still aren't explaining yourself very well. So you can visit example.com/errors/500.html in a browser and see the error page? I don't see how that would work given the second RewriteRule so doubt that is the case. And I've still no idea what you are on about with your test examples. Please explain exactly what you are doing, what is happening, and what you expect to happen. I suspect it's a problem with those rewrite rules so I would comment them all out and then try and see if it works. But that still comes back to the question "how are you creating a 500 error to test this?". Commented Oct 7, 2015 at 21:03
  • @BazzaDP If I navigate to example.com/errors/500.html it gets rewritten as example.com/errors/500 and indeed shows my custom error page. If I navigate to example.com/test, it shows the page test.html. If I try to navigate to example.com/test/, or example.com/test/foo I get the Apache internal server error message. (There is no directory called test). I would expect to see the custom 500 page, considering that's what I set in my ErrorDocument rule in htaccess
    – binaryfunt
    Commented Oct 7, 2015 at 21:27

2 Answers 2


I would try two things -

  1. Check permissions of 500.html (try setting it to 777 to be very sure - modify it later).

  2. Try 500.htm (or 500.txt) instead of 500.html (just to be sure that your other rules in htaccess are not messing up with the ErrorDocument 500.html page). Also, remember to change the htaccess ErrorDocument rule to 500.htm (or 500.txt).

Also, as per http://httpd.apache.org/docs/2.4/mod/core.html#errordocument

Although most error messages can be overridden, there are certain circumstances where the internal messages are used regardless of the setting of ErrorDocument. In particular, if a malformed request is detected, normal request processing will be immediately halted and the internal error message returned. This is necessary to guard against security problems caused by bad requests.

Try some other ways to simulate 500 error.

  • Forgive me, but how can I check permissions of 500.html? According to Microsoft, 777 is The connection attempt failed because the modem or other connecting device on the remote computer is out of order. How would I be able to get a 777 error nowadays?
    – binaryfunt
    Commented Oct 7, 2015 at 20:34
  • 1
    If you can visit the page manually, as per your reply to my comment, then it's not a permission error. Commented Oct 7, 2015 at 20:48
  • I meant permission of the file be set to 777 (readable, writable and executable by everyone) in linux.
    – Aakash
    Commented Oct 7, 2015 at 21:35
  • Ah. But I think it's the malformed request that happens as a result of the rewrite loop (mentioned by w3d)
    – binaryfunt
    Commented Oct 7, 2015 at 22:29

but when I encounter a 500 Internal Server Error, it gives the default Internal Server Error

The problem is that custom 500 error documents defined "late" in .htaccess simply don't get triggered for the majority of server errors - which is what's likely happening here. As Aakash has already quoted, this may come under the realm of a "malformed request". If you check your error log it should state: "core:error".

You stand a better chance of the custom 500 error document being served if it is defined "early" in the main server config (or VirtualHost container).

In fact, it is a bit tricky to simulate a real error that will trigger the custom 500 error document defined in .htaccess.

However, you can manually trigger a 500 error, which will call your custom error handler with something like the following:

RewriteRule ^ - [R=500]

The check against the REDIRECT_STATUS env var ensures that the internal request for the error document itself does not trigger another 500 error, but a direct request for the error document would also trigger a 500 error. This check is not necessary if you already have an exception in place for error documents.

Additionally, a 500 Internal Server Error error was encountered while trying to use an ErrorDocument to handle the request.

This does literally mean that in addition to the 500 error that resulted from the initial request, another 500 error was encountered when trying to serve the custom error document (that is called via an internal subrequest).

The custom error document itself is also processed by the Apache config/.htaccess.

Generally, exceptions need to be made for custom error documents so they can be served without additional processing.

More info: I can get it to throw 500 if I type a trailing slash on a .html page that has had the ".html" removed...

Not sure that this is really part of your question, but this 500 error is the result of a rewrite loop. Specifically:

RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.+)$ $1.html [L,QSA]

Request: http://example.com/test/ (with the extra slash)

In this case the %{REQUEST_FILENAME} is /path/to/test (no trailing slash), so the condition %{REQUEST_FILENAME}.html -f is true (/path/to/test.html does exist).

However, the URL-path that is captured by the RewriteRule pattern does contain the trailing slash ie. test/ - it is not the same as the REQUEST_FILENAME in this instance. So the URL gets incorrectly rewritten to test/.html.

And the rewriting starts over again from the top (because the URL has changed)... test/.html.html, test/.html.html.html, etc. (Because the REQUEST_FILENAME is always /path/to/test.)

  • I thought the same as you initially, but the rewrite is an internal rewrite so does not get returned to the client as a 301 nor should Apache apply the rewrite rule again (as L is set), and even if it did, the condition stating the "%{REQUEST_FILENAME}.html -f" exists would fail as it would look for .html.html the second time rather than test.html. Though I think you're probably on the right track anyway. Commented Oct 7, 2015 at 20:57
  • @BazzaDP Yes, it's an internal rewrite (I'm not sure of the relevance of whether it gets returned to the client or not?). The L flag simply stops the current round of processing (it doesn't stop all processing like the END flag). Since the URL has been rewritten/changed, the processing starts again from the top (because it is an internal rewrite). In this instance the value of REQUEST_FILENAME does not change because everything after /test is stripped (in fact, everything after the last matched directory + filename is stripped), so the same success condition is performed each time.
    – MrWhite
    Commented Oct 7, 2015 at 22:09
  • @BazzaDP I've run some tests on my own server and that is what appears to be happening.
    – MrWhite
    Commented Oct 7, 2015 at 22:10
  • 2
    Interesting. I didn't know that the processing starts again on a rewrite! I, incorrectly, thought you were assuming it was a 301 and so was leading to the client requesting it again and that was causing the loop. Surprised this doesn't lead to lots of rewrite loops - though I do see now that there is warning of this in the Apache docs. Very good Commented Oct 7, 2015 at 22:27
  • If the custom error page would be error.php, how would the entire .htaccess rule have to read? Commented Jun 6, 2022 at 15:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.