К содержимому
Hub
All notes

August 24, 2026 · 3 min read

The button does nothing when you press it

Next.jsReactОтладкаИнтерфейс

Messaging stopped working on the site. The symptom was singular and nasty: you press «Write» and absolutely nothing happens. No navigation, no error, no spinner. The button appears dead.

That is worse than an honest failure. An error with text tells you what to do. Silence tells you nothing — the visitor concludes the site is broken and leaves.

There were three causes, stacked on top of each other.

First: a server action can throw instead of returning a refusal. That is what happens when the session expires — the requireUser guard does not answer «not allowed», it throws. In a click handler without try/catch the exception is lost, and the function never reaches the line that would show something.

Second: the action succeeded but navigation did not happen. router.push called immediately after a server action silently did nothing for us: the conversation appeared in the database while the page stayed put. Digging into exactly why turned out to cost more than replacing it with a plain window.location.assign, which does what it says at the price of a full reload nobody notices here.

Third, the most annoying: the destination page was throwing a server error — that has its own note. So even if the first two had worked, the visitor would have landed on a 500.

The lesson worth keeping: an interface must not have a «nothing happened» state. Every press has to end in one of three things — it worked, it did not and here is why, or it is loading. If the code can exit a handler having shown nothing, sooner or later it will.

React · TSX
function write(userId: string) {  start(async () => {    try {      const result = await openConversation(userId);      if (result.ok && result.conversationId) {        // Обычный переход, а не router.push: тот, вызванный сразу        // после серверного действия, молча не срабатывал.        window.location.assign(          `/${locale}/account/messages/${result.conversationId}`,        );      } else {        setSearchNote(result.message ?? "Не удалось открыть переписку");      }    } catch {      // Действие может БРОСИТЬ, а не вернуть отказ — например, когда      // истекла сессия. Без перехвата кнопка молча не делала бы ничего.      setSearchNote(        "Не получилось — возможно, истёк вход. Обновите страницу и войдите заново.",      );    }  });}