Under the hood the routing dependency converts each path from the Route subclasses to an anvil.server.route
And so if there is no registered route for a bad path then anvil will treat it as not having a matching end point.
When navigating on the client we can handle bad paths since we are not routing via the server.
A possible option might be to define a splat like route at the end of you routes. Something like:
class Splat(Route):
path = "/:x"
not_found_form = "Pages.NotFound"
def before_load(self, **loader_args):
raise NotFound