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.
tscchecks types, not where code runs. Storybook is a client-only app.bun run checkdoes not build the Next app.next builddoes 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
RunDone in chapter 39: every pull request builds the web app (guide 20).bun run buildin CI, so a design-system change that breaks the app cannot be merged.- Consider rendering agent pages through Next as well, at least for tasks whose page is a server component. It is slower; measure before deciding.
The args Panda never saw
The first Stack and Grid stories passed their layout through Storybook args. They rendered with no gap, no responsive row and no columns, and no tool said a word.
Valid and empty
Two generated UI specs passed json-render's validation and showed nothing. The root pointed at an element that was never written, and the check that said so was a different function.