Ultimate · errors & dead ends

When it breaks, get quieter

Every broken, interrupted, or dead-ended state, drawn in the app's calm register. The whole point of this board: a broken moment stays ink and muted — it never borrows a sunset accent. Tangerine means live, marigold means Starter, rose means Celebrator / finale — those stay semantic, so an error rendered in alarm color would read as a broken promise, not a hiccup. Voice is plain and blame-free; retry is the single way forward; nothing already loaded is thrown away; and a dead-end never reveals whether the door was closed by a delete or a block.

The visual thesis, in one line: errors are ink and muted — never an accent, never red. No “Oops”, no exclamation marks, no error codes, no sad-face mascots. The app answers a broken moment by getting quieter, not louder.

01 Offline — cold load

The feed opened with no connection and nothing cached. A full-screen quiet state, sibling to the empty states: ink glyph, calm headline, one muted sentence, a quiet ink-outline Retry — no accent, no alarm.

You're offline.
Your people's steps will be here when you're back.

Offline is a fact, not a failure

The app states it once and waits. No spinner held forever, no scolding, no big red banner — just the plain sentence and a way to nudge it. The glyph is two stepping-stones with a gap, original and quiet: no wifi-slash, no cloud.

  • The app auto-retries on reconnect — the button is only there for impatience.
  • Ink outline, transparent fill: Retry is a quiet option, never a hero CTA.
  • Nothing accented, because being offline is nobody's fault and no emergency.

02 Couldn't load more

Pagination failed mid-scroll. Everything already loaded stays; one quiet inline row does the recovery. This is the canon dressing for the app's existing list error-recovery — it never takes over the screen.

Maya Okonkwo
@mayaruns · 15h ago
Ran the whole loop without walking for the first time. Five weeks ago the first minute wrecked me.
Couldn't load more Retry

The list keeps what it has

A failed page never blanks the feed or throws up a modal. The cards you already scrolled stay exactly where they are; the fade at the bottom edge shows the list simply stopped, and one centered row offers to fetch the rest.

  • Muted “Couldn't load more” + an underlined ink Retry link — body weight, no button chrome.
  • Retry re-requests only the next page; the loaded ones are never re-fetched or lost.
  • No accent, no icon, no count of what failed — one quiet line is the whole treatment.

03 Your step didn't post

Publishing failed after you hit post. The composer keeps everything local until the server confirms, so nothing you wrote or picked is gone. A bottom sheet says so and offers to re-send it as-is.

Your step didn't post.

It's still here — nothing you wrote or picked is lost.

Nothing is lost while the server catches up

The note and media are held on the device the whole time; a failed publish just means the app hasn't heard back yet. Try again re-sends the identical draft — same words, same photo, same order.

  • Try again is the single ink CTA; it re-sends note + media exactly as composed.
  • Discard step is the only place that word appears — and it's muted, never red.
  • No accent on the sheet: a delivery hiccup is not a live moment and not an alarm.

04 This step is no longer here

A deep link resolved to something you can't see. A full-screen dead-end: ink glyph of a pill with a soft opening — a door left ajar — a calm headline, one muted line, and a quiet way back to your feed.

This step is no longer here.
It may have been removed by its author.

A closed door, not a mystery to solve

deleted, author-blocked-you, and you-blocked-author all render this exact screen — indistinguishable by design. There is nothing to diagnose and no one to name; the state is the same door whichever reason closed it.

  • The server answers identically too — the client cannot tell the three apart, so nothing leaks.
  • Same dressing serves other nouns: “This journey…” / “This profile…”, copy swapped, screen unchanged.
  • Ink glyph, ink-outline button, no accent — a dead-end is quiet, never accusatory.

05 Media that won't load

One card's image failed to fetch. The card keeps its full reserved height and the media area becomes a calm field — no broken-image icon, no gray X. Tapping retries just that one image.

Daniel Alvarez
@danbuilds · 3h ago
Framed the last wall of the workshop today. First time the whole thing has stood square.
Tap to reload

The layout never collapses

Every step has media, so the card reserves its aspect ratio no matter what. A failed image doesn't shrink the card, jump the scroll, or stamp a broken-image glyph — it fills the same space with a quiet paper field and a faint prompt.

  • A faint centered pill-glyph + “Tap to reload” in --faint — no icon of failure.
  • Media keeps its reserved height; the rest of the card is fully usable meanwhile.
  • Tap retries only this image, not the card, not the page.

06 Something went wrong

The last-resort catch-all, used only when nothing more specific is known. Still a full-screen quiet state — plain headline, one reassuring line, the same ink-outline Retry.

That didn't work.
Try again in a moment — we're on it.

Generic, and deliberately vague

When the app genuinely doesn't know what broke, it says so plainly and offers one button — it does not invent a specific-sounding excuse. Everything an engineer needs is already elsewhere.

  • Error codes, stack traces, and diagnostics go to logs — never onto the screen.
  • No “Oops”, no sad-face mascot, no exclamation marks anywhere in error copy.
  • Used last: any state with a truer message (offline, dead-end, failed post) wins over this one.

07 Bright lines

The rules that keep every broken state calm, honest, and free of blame — the spine every surface above is drawn from.

The bright lines for errors

When something breaks, the app gets quieter, not louder.

Scope & status. This board covers every broken, interrupted, or dead-ended surface in the app's calm register — the sibling of states-empty.html. The first-run and honest-zero surfaces live there; the interrupted and failed surfaces live here. Both share one doctrine: the app never manufactures alarm. Full-screen states reuse the empty-state grammar (glyph · headline · sentence · one quiet action); the inline “Couldn't load more” row is the canon dressing for the list's existing error-recovery; and the deep-link dead-end (panel 04) is the single screen behind which delete and block are made indistinguishable — enforced on the server, not just the client, so no reason ever leaks.