@Angelo Melino I always try the so-called operator form calling sequence of evalf(Int(...)) when trying to handle difficulties. By that I mean that the integrand is supplied as an operator or procedure. In part I do so because it's one way to forcibly skip the (sometimes very expensive) symbolic continuity check of the integrand.
For your example that showed me that evalhf was balking on the LegendreP call.
The precise error message coming out of evalhf was unfamiliar to me, which is somewhat unusual. Now, some commands that have both fast evalhf modes and slower/fallback evalf mode will try...catch the former. Some of these commands are coded to do the fallback only if the error is an, ummm, "non-evalhf'ability error", where the code is manifestly non-evalhf'able. If another kind of deeper problem occurs with the call then there may be little merit in falling back to evalf; that is a rationale, for good or bad. But this approach is not robust unless it can be coded to catch all the sorts of error that typically arise when trying to evalhf a call that is non-evalhf'able (given that earlier code ensures that the call is otherwise correct up to a point).
Another approach is to fall back to evalf upon any error encountered during an earlier evalhf attempt.
I have seen both kinds of approach: the blanket fallback and the fallback only on certain caught errors. Eg, in plotting, Optimization, evalf(Int(...)), etc.
Since the error message I saw here was unfamiliar to me, it occurred to me that it might just be the case that the fallback was not being tried, perhaps just because the mechanism was not coded to catch this particular error message from evalhf. So I forced another kind of evalhf error.
I have not taken the time yet to run it all in the debugger and see whether my suppositions are correct about this example.
It can get ricky, to provide fast evalhf mode alongside an evalf fallback. Other subtleties include detecting and passing back errors in the user's whole formulation, ascertaining which errors to re-throw and which to subsume, etc.
Automatic fallback mechanisms are nice for users, but also harder to maintain. One danger is that an upstream method can be accidentally broken while that fact is obscured by the very robustness of the mechanism.