Custom WP_Query always respond with 200 status even when no entry

Response is based on the results of the main query. The decision is made before the template is loaded, which is how WP is able to serve a 404 template in the case of a 404.

As you’ve learned, the page post type lets you paginate endlessly in both the format pagename/page/n/, as well as the singular pattern pagename/n/. To generate a 404 for a different query, you’d need to hook something like template_redirect to check if your custom query contains posts so you can force a 404 before output starts.

The preferred solution is to set the has_archive argument for your custom post type, which enables an archive page. The main query will then be your collection of portfolio posts, and pagination will work as expected.