streamText returns immediately with a stream object and does not await the model call, so an error from the provider is not thrown from the call site. A try block wrapped around streamText catches nothing. The error surfaces as an error part on the stream, through the onError callback, or when you await one of the resolved promises such as the final text or usage.
This is deliberate, because a stream may fail partway through after some content has already been delivered, and there is no way to un-send that.
Always pass onError and log there, otherwise provider failures are swallowed and appear as an empty response. Note also that errors are not forwarded to the client by default when the stream is converted into a response, to avoid leaking provider details; you supply a function that maps the error to a message you are willing to expose. And onFinish may never run if the client disconnects mid-stream, so anything that must happen exactly once, such as persisting the assistant message, needs the stream consumed server-side rather than relying on that callback alone.