Respond status code behavior within handle_errors

1. The problem/doubt I’m having:

Hi!

When using respond directive within handle_errors directive without specifying a response status code, the original error status code is returned to the client along with the specified body, right?

For example:

handle_errors {
	@404-410 `{err.status_code} in [404, 410]`
	handle @404-410 {
		respond "It's a 404 or 410 error!"
	}

	@5xx `{err.status_code} >= 500 && {err.status_code} < 600`
	handle @5xx {
		respond "It's a 5xx error."
	}

	handle {
		respond "It's another error"
	}
}

In the previous example, if a 502 error occurs, the execution will enter through the second block, so the response will be the following:

~ ❯ http https://example.dev
HTTP/1.1 502 Bad Gateway
Alt-Svc: h3=":443"; ma=2592000
Content-Length: 17
Content-Type: text/plain; charset=utf-8
Date: Wed, 04 Sep 2024 16:33:57 GMT
Server: Caddy

It's a 5xx error.

If I want to return a 200 status code, would I have to explicitly specify it in the respond directive? As far as I see in the documentation of the respond directive, by default, if no other status code is specified, it sets 200. But this is not the case. Does this behavior change when used within the handler_errors directive?

Thanks in advance.

Regards!

2. Error messages and/or full log output:

-

3. Caddy version:

2.8.4

4. How I installed and ran Caddy:

-

5. Links to relevant resources:

-

I think the docs for the respond directive specify a default status of 200 because 200 is the default status returned by Caddy when no other status was generated.

Essentially, a totally empty route returns 200 OK.

Specifically not overriding that would normally leave it as a 200 response.

In the case of errors, though, we have a specific status code being written and not overriding it with respond leaves it as whatever it was before we reached that handler.

If you take a Caddyfile and adapt to JSON to see what it’s doing you can kinda see why:

handle_errors {
  respond "{err.status_code} {err.status_text}"
}

This produces JSON:

          "errors": {
            "routes": [
              {
                "match": [
                  {
                    "host": [
                      "example.com"
                    ]
                  }
                ],
                "handle": [
                  {
                    "handler": "subroute",
                    "routes": [
                      {
                        "handle": [
                          {
                            "body": "{http.error.status_code} {http.error.status_text}",
                            "handler": "static_response"
                          }
                        ]
                      }
                    ]
                  }
                ],
                "terminal": true
              }
            ]
          }

But if you specify respond "{err.status_code} {err.status_text}" 200 you get an extra "status_code": 200 being configured:


          "errors": {
            "routes": [
              {
                "match": [
                  {
                    "host": [
                      "example.com"
                    ]
                  }
                ],
                "handle": [
                  {
                    "handler": "subroute",
                    "routes": [
                      {
                        "handle": [
                          {
                            "body": "{http.error.status_code} {http.error.status_text}",
                            "handler": "static_response",
                            "status_code": 200
                          }
                        ]
                      }
                    ]
                  }
                ],
                "terminal": true
              }
            ]
          }

So it’s not the case that respond (i.e. the static_response handler) sets 200 by default, more specifically that it simply doesn’t alter the status unless you specify it.

2 Likes

Also FWIW, you can simplify by using the new syntax for handle_errors where it takes status codes as input. For example:

handle_errors 404 410 {
	respond "It's a 404 or 410 error!"
}

handle_errors 5xx {
	respond "It's a 5xx error."
}

handle_errors {
	respond "It's another error"
}
3 Likes

That’s so good! Thank you very much!