Skip to Content
Vektos
Anecdotes

The toast that took every page down

A design-system module that created its toaster at import time crashed every page of the dashboard, including the ones without a toast. Every check passed; only the Next build and a browser saw it.

Date: 2026-11-09. Context: the feedback components (feat/ds-feedback, guide 06).

What happened

toast.tsx creates one toaster for the whole app, at the top of the module:

const store = createToaster({ placement: "bottom-end", overlap: false, gap: 12, max: 4 });

Types, lint, 457 tests, Storybook and 32 axe checks on the new stories: all green. Then the dashboard, opened in Chrome for its usual axe pass, failed on every page with the same two problems, no <title> and no lang. That is what a page looks like when Next renders its error screen instead.

The server log said why: "Attempted to call createToaster() from the server but createToaster is on the client." Ark marks its modules "use client". The dashboard's pages are server components, they import Card or Badge from @vektos/ds, and @vektos/ds is one barrel file. Importing the barrel evaluates every module in it, toast.tsx included, and its first line of real code called a client function on the server. No page used a toast. All of them broke.

The fix is one line, "use client" at the top of toast.tsx: the module becomes a client module, evaluated only in the browser, and a server component can still import Toaster and render it.

What we learned

  • A side effect at import time belongs to every consumer. A component that does nothing until rendered is safe in a barrel. A module that calls something when it loads runs for every page that imports anything from the package.
  • The checks that passed could not have seen it. tsc checks types, not where code runs. Storybook is a client-only app. bun run check does not build the Next app. next build does fail ("Failed to collect configuration for /"), and so does any page in a browser.
  • The symptom pointed away from the cause. "No title, no lang" on every page reads like a layout bug. The log had the answer on its first line.

What it means for Vektos

The benchmark renders an agent's page by bundling it for the browser (Bun.build, guide 11), not through Next's server components. A design system with this bug would pass every page in the benchmark and break every page in a real app. The opposite case also exists: an agent that calls toast() from a server component gets a clear error in Next, and nothing in the benchmark's render. Server and client are a dimension the page checks do not cover yet.

Follow-ups

  • Run bun run build in CI, so a design-system change that breaks the app cannot be merged. Done in chapter 39: every pull request builds the web app (guide 20).
  • Consider rendering agent pages through Next as well, at least for tasks whose page is a server component. It is slower; measure before deciding.

On this page