I want to point out that these are not questions around the Java Client or any client, but rather about how Elasticsearch works.
On throwing exceptions only for total failures, that is just how Elasticsearch works, the idea is to return some results if we have any, and to include in the response some info that tells users that they were partial results. Failures can happen in a distributed system and this is to some degree a way to be tolerant to failures. Of course it always depends on what the most important aspect is, depending on the application. We've been discussing about making this more explicit through a new flag, and changing the default behaviour, see https://github.com/elastic/elasticsearch/issues/28494.
When it comes to an indexing operation, things are quite different. First of all when you index a document, that document is supposed to go to one single shard, plus all of its replicas. If the indexing operation succeeds on the primary, and some replica fails, we will mark the replica failed and try to fix it, most likely by recreating it on another node. You will be notified of this through the
_shards section that the index API returns. I am simplifying things here, bare with me. On the other hand if the operation fails on the primary, you will get back an error. The index operation is to be considered failed when an exception is returned.
Also, do keep in mind that searching for something through the search API may not return a document that was just indexed, as a refresh may not have happened between the index operation and the search, which is required to make newly indexed documents visibile to the search API. That does not mean that such documents are not there though, they are and this is not a matter of consistency, it is just how the search API works.