It sounds like an underlying problem was that server side and client side validation errors weren’t treated the same way.
It doesn’t matter whether they come from your server, from frontend validators, or even other servers. And it doesn’t matter if they’re set in response to onBlur or onChange (although of course that’ll affect UX).
What matters is that you establish a uniform data structure for describing field errors and non-field errors, then use it consistently to set the form error state.
That way whether it’s frontend validation code or response handling code that sets the error state (the choice is yours, or your Disney overlord’s!), you don’t have to have duplicate error handling at the form level.