Error when using handle_errors inside route

1. Caddy version (caddy version):

2.4.3

2. How I run Caddy:

a. System environment:

Windows 10 Build 19043

b. Command:

caddy run -watch

c. Service/unit/compose file:

N/A

d. My complete Caddyfile or JSON config:

{
	auto_https off
	debug
}

www.erindachtler.me {
	redir https://erindachtler.me{uri}
}

erindachtler.me, :80 { # :80is for testing
	encode gzip zstd

	handle_path /pomodoro/* {
		root content/elm-pomodoro/dist/
		file_server
	}

	route /romans/* {
		root content/romans-pizza/public/
		uri strip_prefix /romans

		try_files {path}.html

		file_server {
			hide 404.html
		}

		handle_errors {
			@404 expression `{http.error.status_code} == 404`
			try_files @404 /404.html
			file_server
		}
	}

	route {
		root content/resume
		file_server
	}
}

3. The problem I’m having:

I’m trying to put some static projects into directories on my server.
In the case of one of these (romans) I want to display a 404 page on no matching files.
It seems to be giving some kind of error about handle_errors not being allowed inside a route block.
I would think handle_errors would count as a “handler directive” since you are presumably going to handle the error inside it.

Is this a bug, or am I not using the directives correctly?

4. Error messages and/or full log output:

2021/07/25 15:45:53.081 INFO    using adjacent Caddyfile
run: adapting config using caddyfile: parsing caddyfile tokens for 'route': Caddyfile:36 - Error during parsing: handle_errors directive returned something other than an HTTP route or subroute: &caddyhttp.Subroute{Routes:caddyhttp.RouteList{caddyhttp.Route{Group:"", MatcherSetsRaw:caddyhttp.RawMatcherSets{caddy.ModuleMap{"file":json.RawMessage{0x7b, 0x22, 0x74, 0x72, 0x79, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x40, 0x34, 0x30, 0x34, 0x22, 0x2c, 0x22, 0x2f, 0x34, 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x5d, 0x7d}}}, HandlersRaw:[]json.RawMessage{json.RawMessage{0x7b, 0x22, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x22, 0x3a, 0x22, 0x72, 0x65, 0x77, 0x72, 0x69, 0x74, 0x65, 0x22, 0x2c, 0x22, 0x75, 0x72, 0x69, 0x22, 0x3a, 0x22, 0x7b, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x73, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x7d, 0x22, 0x7d}}, Terminal:false, MatcherSets:caddyhttp.MatcherSets(nil), Handlers:[]caddyhttp.MiddlewareHandler(nil), middleware:[]caddyhttp.Middleware(nil)}, caddyhttp.Route{Group:"", MatcherSetsRaw:caddyhttp.RawMatcherSets(nil), HandlersRaw:[]json.RawMessage{json.RawMessage{0x7b, 0x22, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x22, 0x3a, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x2c, 0x22, 0x68, 0x69, 0x64, 0x65, 0x22, 0x3a, 0x5b, 0x22, 0x2e, 0x5c, 0x5c, 0x43, 0x61, 0x64, 0x64, 0x79, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x5d, 0x7d}}, Terminal:false, MatcherSets:caddyhttp.MatcherSets(nil), Handlers:[]caddyhttp.MiddlewareHandler(nil), middleware:[]caddyhttp.Middleware(nil)}}, Errors:(*caddyhttp.HTTPErrorConfig)(nil)} (only handler directives can be used in routes)

5. What I already tried:

Tried using handle_path instead of route but it said that’s not allowed:

parsing caddyfile tokens for 'handle_path': directive 'handle_errors' is not ordered, so it cannot be used here

The handle_errors directive is a bit special – it must be used as the top-level, because it’s a site-wide error handler, not per route. You may use a matcher/routes within your handle_errors block though.

The way handle_errors works is as an alternate request handling chain, so if any error is encountered in that site (errors emitted by Caddy), it will then pass it through the error handler chain if configured. It’s not really conditionally registered; it’s either defined or it’s not.

You can use handle_path instead of route + uri strip_prefix here to save a line, since handle_path has built-in prefix stripping behaviour.

1 Like

Thanks! I was able to fix it by moving the handle_errors block to the root of the site block and duplicating the path matching inside it.

handle_errors {
	@romans404 {
		path /romans/*
		expression `{http.error.status_code} == 404`
	}

	route @romans404 {
		root content/romans-pizza/public/
		try_files @404 /404.html
		file_server
	}
}
2 Likes

This topic was automatically closed after 30 days. New replies are no longer allowed.