Coté controlleur il faut juste throw quand on a un pb.
sinon les erreurs sql ou autre throw par elles mêmes.
On rentre donc dans le catch global de la route
try { throw new Error('suce'); } catch(err) { next(err) }
Ensuite, si c'est un appel ajax, ou un bot ou un curl, cela transforme l'output en json au lieu de renvoyer du html.
donc coté front il faut juste appeller
try { // appel ajax ou autre catch(err) { show_errorModal(err); }
l'erreur contient alors une erreur front normale (syntaxe, erreur de parsing json) qui est affichée tel qu'elle.
Ou une erreur ajax dont le responseText est parsé automatiquement pour afficher le bon message en front.