NS Design System
v3.0.0 · 257 tokens

119Errors & limits

Failures render inside the transcript, in the assistant's own slot, because that is where the student is already looking and because a failed turn must stay in the record. The 3px leading edge is the system's error device; the retry is an outline button — the primary action on the screen is still the composer.

Use it for

  • A tool or model failure, in the turn it happened in
  • --limit for a quota the student fixes by waiting or upgrading, not by retrying
  • --offline for a lost connection, where nothing is wrong with the question

Not for

  • A toast — a toast disappears, and the student needs to see which question failed
  • Blaming the student: “something went wrong” with no state about what survived is worse than the error

Tool failure

Assistant
markup
<article class="ns-aiturn ns-aiturn--agent" data-state="error" style="max-inline-size:40rem">
  <header class="ns-aiturn__head"><span class="ns-aiturn__mark" aria-hidden="true"><i class="ph ph-sparkle"></i></span>Assistant<time datetime="2026-03-04T09:19">09:19</time></header>
  <div class="ns-aierror" role="alert">
    <p class="ns-aierror__head"><i class="ph ph-warning-circle" aria-hidden="true"></i> Could not reach the catalog</p>
    <p class="ns-aierror__text">The explanation above is written from what I already know about your progress; the course list needs the catalog and it did not respond. Nothing you typed was lost.</p>
    <div class="ns-aierror__actions">
      <button type="button" class="ns-btn ns-btn--outline ns-btn--sm"><i class="ph ph-arrow-counter-clockwise" aria-hidden="true"></i> Try again</button>
      <a class="ns-btn ns-btn--quiet ns-btn--sm" href="#0">Report this</a>
      <span class="ns-aierror__code">ERR_TOOL_TIMEOUT · 09:19:04</span>
    </div>
  </div>
</article>

Daily limit

Warning, not error: nothing is broken and retrying will not help. The upgrade is an outline button beside a plain “comes back at midnight”, because a paywall that shouts is a paywall people resent.

markup
<div class="ns-aierror ns-aierror--limit" role="alert" style="max-inline-size:40rem">
  <p class="ns-aierror__head"><i class="ph ph-timer" aria-hidden="true"></i> That is your 30th question today</p>
  <p class="ns-aierror__text">The free plan resets at midnight — your history, saved paths and this conversation are all still here. Pro removes the cap.</p>
  <div class="ns-aierror__actions">
    <button type="button" class="ns-btn ns-btn--outline ns-btn--sm">See Pro</button>
    <span class="ns-aierror__code">resets in 6h 12m</span>
  </div>
</div>

Offline

Muted, not red. A dropped connection is not a failure of the answer, and colouring it like one teaches students to ignore the colour.

markup
<div class="ns-aierror ns-aierror--offline" role="alert" style="max-inline-size:40rem">
  <p class="ns-aierror__head"><i class="ph ph-plugs" aria-hidden="true"></i> You are offline</p>
  <p class="ns-aierror__text">Your question is saved in the box and will send when the connection is back.</p>
  <div class="ns-aierror__actions">
    <button type="button" class="ns-btn ns-btn--outline ns-btn--sm"><i class="ph ph-arrows-clockwise" aria-hidden="true"></i> Retry now</button>
  </div>
</div>

Refused

The one the LMS actually needs: a student asking for the graded assignment's answers. It says no, says why once, and offers the thing it CAN do — no lecture.

markup
<div class="ns-aierror ns-aierror--limit" role="alert" style="max-inline-size:40rem">
  <p class="ns-aierror__head"><i class="ph ph-shield-check" aria-hidden="true"></i> I will not answer the graded assessment</p>
  <p class="ns-aierror__text">This one is marked, and handing you the answer is the one thing that would not help. I can walk you through the concept it tests, or review an attempt you have written.</p>
  <div class="ns-aierror__actions">
    <button type="button" class="ns-btn ns-btn--outline ns-btn--sm">Explain the concept</button>
    <button type="button" class="ns-btn ns-btn--quiet ns-btn--sm">Review my attempt</button>
  </div>
</div>

Accessibility contract

  • role="alert" on the block, so the failure is announced when it lands
  • The technical code is present, in mono — a student pasting ERR_TOOL_TIMEOUT into a ticket is doing support's job for them
  • Always says what happened to the input: “nothing you typed was lost” is the sentence people are looking for