Почему пользователи не видят сообщение об ошибке — 3 причины и как проверить

Симптом всегда один и тот же: человек пишет «я нажал кнопку, ничего не произошло». Ты открываешь код — сообщение об ошибке есть. Проверяешь у себя — видно. Смотришь запись сессии — человек жмёт кнопку восемь раз подряд и уходит.
Ошибка отобразилась. Просто не там, не тогда или не так, чтобы её заметили. Разберём три причины по частоте — почти всегда это одна из них.
Причина 1: сообщение вне того, что видно на экране
Самая частая и самая незаметная в разработке.
Форма длинная. Поле «Почта» — вверху, кнопка «Отправить» — внизу. Человек жмёт, ошибка появляется у поля почты — на два экрана выше. Страница осталась на месте. Для человека не произошло вообще ничего.
У тебя это не воспроизводится, потому что на большом мониторе форма помещается целиком.
Как проверить. Открой форму, сожми окно браузера по высоте до размера телефона, прокрути к кнопке и отправь пустую форму. Если экран не сдвинулся — вот она, причина.
Как починить. После неудачной отправки прокрути страницу к первой ошибке и переведи туда фокус:
const firstInvalid = form.querySelector('[aria-invalid="true"]');
firstInvalid?.focus(); // фокус сам прокрутит к элементу
firstInvalid?.scrollIntoView({ block: 'center', behavior: 'smooth' });
Именно фокус, а не только прокрутка: он одновременно решает задачу для клавиатуры и для скринридера. И ставить его надо на само поле, а не на текст ошибки — человеку сразу нужно печатать.
Причина 2: ошибка ушла в консоль, а не в интерфейс
Второй по частоте случай — и он почти всегда родом из кода, который писали быстро:
try {
await api.save(data);
} catch (e) {
console.error(e); // ← весь UI об ошибке
}
Для тебя ошибка «есть»: она в консоли, ты её видишь при отладке. Для пользователя её не существует — консоль он не открывает никогда.
Как проверить. Найди в проекте все catch и посмотри, что внутри. Если там только console.error или пустые скобки — это молчаливая потеря:
grep -rn "catch" src/ | grep -v "setError"
Как починить. Правило: любой catch, который обрабатывает действие пользователя, обязан изменить состояние интерфейса. Не «залогировать», а изменить: сбросить спиннер, показать текст, вернуть кнопку в рабочее состояние.
Отдельная разновидность той же беды — когда запрос вообще не упал, но вернул не то, что ты ждал: сервер ответил 200, а в теле пусто. Тогда ошибки нет ни в консоли, ни в интерфейсе — типичная история неопределённого ответа. Проверяй не только catch, но и то, что пришло.
Причина 3: сообщение показалось и исчезло
Третий вариант — ошибку показали тостом на три секунды.
Человек в этот момент смотрел на кнопку, а плашка вылезла в правом верхнем углу. Или смотрел куда надо, но читает медленнее. Или это телефон, и плашка снизу накрыла кнопку — он ткнул ещё раз и закрыл её собственным нажатием.
Сюда же — случай, когда сообщение видно, но недоступно тем, кто пользуется скринридером. Блок, просто вставленный в разметку, озвучен не будет: чтобы его прочитали, нужна «живая область», которая лежит в разметке заранее и пустой, а текст появляется внутри неё:
<div id="form-status" role="status"></div>
Как проверить. Спроси у человека, который жаловался, одну вещь: «мелькнуло ли что-нибудь». Ответ «вроде что-то было, я не успел прочитать» — это точный диагноз.
Как починить. Ошибки формы не показывай тостом вообще — им место у поля. Разбор по критериям есть в тост или ошибка под полем. Если ошибка общая (упала сеть, сервер вернул 500) — оставь текст рядом с кнопкой, где он и останется до следующей попытки, а плашке сними таймер.
Если всё видно, а его всё равно не понимают
Бывает и четвёртый слой: сообщение на экране, человек его прочитал — и не понял, что делать.
Три частых виновника:
- Цвет вместо текста. Красная рамка без подписи не читается ни скринридером, ни человеком, который не различает красный.
- Слишком общая формулировка. «Ошибка валидации» не говорит, какое поле и что с ним не так. Нужно и то и другое: какое поле, что не так, каким должно быть.
- Технический текст как есть.
Unexpected token < in JSON at position 0— это сообщение для тебя, а не для пользователя. Что оно означает, разбирается в как читать сообщение об ошибке; пользователю показывай человеческую фразу, а техническую убирай в логи.
Как проверить всё за одну минуту
Сожми окно браузера до высоты телефона. Отправь пустую форму. Не прокручивая, посмотри: экран сдвинулся к ошибке? Текст остался на месте через десять секунд? Понятно, какое поле чинить?
Три «да» — проблемы нет. Любое «нет» — ты нашёл свою причину.
Может, дело в CSS, и блок просто невидим?
Такое бывает: элемент есть в разметке, но скрыт стилями или спрятан за другим блоком. Проверяется в инспекторе за десять секунд — и, если да, это уже другая история про CSS.
Нужно ли показывать код ошибки пользователю?
Короткий идентификатор — полезно, если у тебя есть поддержка: человек назовёт его, и ты найдёшь запись в логах. Но идентификатор идёт после человеческого объяснения, а не вместо него.
Как отловить это заранее, без жалоб?
Считай в аналитике повторные нажатия одной кнопки за короткий промежуток. Три нажатия за пять секунд — почти всегда значит, что человек не получил обратной связи.
Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.





