Исключение всегда должно указывать на *исключительную* ситуацию, то есть ту, которой быть не должно. Например, сдох диск, не хватило памяти или ещё что-то настолько же катастрофичное. Такая ситуация, после которой мы вообще не уверены, сможет ли программа работать. Поэтому делаем аварийное завершение.
Если же это просто редкая, но нормальная ситуация, такая как некорректный ввод данных, то это должно быть предусмотрено и обработано без исключений. 404 не является ошибкой логики приложения. Не является сбоем оборудования. Мы всегда знаем, как обработать эту ситуацию. Поэтому исключения быть не должно, должен быть просто ответ 404.
Иногда разработчики пытаются сделать общение между объектами через исключения. Но это тупик. Теряется самое главное преимущество механизма обработки ошибок — возможность видеть внятную общую картину, насколько корректно работает приложение. Мы не можем просто посчитать Exception и сказать, что у нас "ошибка не чаще раз в день", потому что мы должны посчитать всё, потом вычесть 404, а то и 403, всё усложняется...