Quick random thoughts ...
Not sure of the exact use cases for this function design wise, but ...
if I were to use this function to read a config file, the currently implementation would be OK. If an empty string were returned if no file, then defaults could be easily applied.
if the file were needed, my preference is that a check is done before calling the function.
if not FileExists(...) then
begin
HandleError(...)
Exit;
end;
contents := ReadFileToString(...);
Having to use/rely on exception handling makes things harder for the compiler (.exe) and when bad things happen, making a program inefficient.