Adding the parts that are prompting and orchestration, since tool design alone will not get you all the way.
In the system prompt, state the rule explicitly. Something to the effect that if a tool fails, it must be reported and no value may be invented or estimated in its place. It is not a guarantee and it measurably helps, particularly combined with clear error text.
Do not let the agent be the last word on whether it succeeded. If a result is supposed to come from a specific tool, check in your own code that the tool actually returned successfully before you accept the run. That is a five line check and it converts a silent wrong answer into a visible failed run.
Consider failing the run outright for tools where a missing value makes the whole answer meaningless. Not everything should be recoverable, an authentication failure usually means stop, not improvise.
Retry the retryable ones in your code, not by asking the model to try again. An auth error should be surfaced; a transient network error should be retried once before the model ever sees it. Letting the model decide about retries wastes tokens and produces inconsistent behaviour.
The general principle: the model orchestrates, your code enforces. Anything you actually require should be checked outside the model.