When to check for max_num_pages using WordPress REST API?

pre_get_posts does fire for REST requests.

After copying your function and stepping through it, your code is actually working — the first time. However the WP REST controller has the following bit:

        if ( $total_posts < 1 ) {
            // Out-of-bounds, run the query again without LIMIT for total count.
            unset( $query_args['paged'] );

            $count_query = new WP_Query();
            $count_query->query( $query_args );
            $total_posts = $count_query->found_posts;
        }

This re-runs the query, which in turn re-runs your function. However as you can see, it has intentionally unset the ‘paged’ argument, so this time when you compare $currentPage > $lastPage you are comparing 0 > 0 which is false, so your post__in argument is not set, and posts are returned. You know the rest of the story — WordPress then catches that you can’t have that page because there aren’t enough posts.

You could get that parameter more directly since it is part of your GET request, like:

    if( ! is_admin()
        && isset($_GET['page']) ) {
        $currentPage = $_GET['page'];
        $lastPage = $query->max_num_pages;
        if( $currentPage > $lastPage ) {
            $query->set('post__in', array(0));
        }
    }

This seemed to work, but I didn’t test it thoroughly.

To be honest, you are really swimming upstream here, and I think a better solution might be to take a hint from WordPress and just build in handling for that error response. It’s nicely packaged as JSON, and you will probably want to watch for other errors too anyways.

Also, I think your function should check and make sure it is only firing on REST requests. Right now as it is written it would fire on others as well.