Skip to content

refactor(server): sweep three inline errorMessage ternaries onto the shared helper (#tech-debt) - #1079

Merged
selfcontained merged 1 commit into
mainfrom
tech-debt/error-message-sweep-1080
Sep 9, 2026
Merged

refactor(server): sweep three inline errorMessage ternaries onto the shared helper (#tech-debt)#1079
selfcontained merged 1 commit into
mainfrom
tech-debt/error-message-sweep-1080

Conversation

@selfcontained

Copy link
Copy Markdown
Owner

What

Three sites had re-inlined the exact body of errorMessage (apps/server/src/shared/lib/error-message.ts, which is error instanceof Error ? error.message : String(error)). They now import it:

file line before
apps/server/src/agents/pin-write.ts 52 new AgentError(error instanceof Error ? error.message : String(error), 400)
apps/server/src/shared/plugin-status.ts 124 { error: err instanceof Error ? err.message : String(err) }
apps/server/src/shared/mcp/whiteboard-tools.ts 338 `${error instanceof Error ? error.message : String(error)} — call whiteboard_howto …`

+6/-6 across 3 files. The substitution is textual identity — same expression, same result for every input — so there is no behavior change.

Why it's tech debt

Recurring, tracked regression. errorMessage was fully consolidated across the server in #914 and across web in #926 (2026-08-09/10). The Brain's pattern entry predicted a re-sweep every 6–12 months; the 2026-09-05 audit found these three had already crept back within four weeks, and the sharpest signal from #914 was that the helper is not hard to find — it is muscle memory when writing a new try/catch.

What the three included sites have in common — precisely

All three are catch blocks that convert an unknown thrown value to a string using the bare String(x) fallback, with no domain-specific default. In whiteboard-tools.ts the — call whiteboard_howto … suffix sits outside the ternary, so it survives interpolation unchanged.

Deliberate exclusions (do not re-flag)

grep -rn 'instanceof Error' apps/server/src apps/web/src finds 52 sites. The 48 not touched here fall into two groups, and errorMessage cannot express either:

  1. Domain-specific fallback strings (~40 sites) — e.g. release-info.ts : "migration evaluation failed", agents/archive.ts : "Archive failed", http-helpers.ts : "Unknown error.", routes/personas.ts : "Invalid model.", and every web site (use-notification-settings.ts : "Failed to save.", branch-select.tsx : "Couldn't load branches.", …). Swapping in errorMessage would replace a curated user-facing message with String(undefined)-class output. Behavior change, not a sweep.
  2. Type-narrowing guards, not string conversion (~8 sites) — e.g. config.ts: error instanceof Error && error.message.startsWith("Refusing to use"), media-lightbox.tsx, use-chat-surface-enabled.ts, use-terminal.ts, service-resources.ts. These use instanceof to branch, not to stringify.

Also excluded: bin/embed-assisted-update.ts:77,88 carry the same ternary, but bin/ is a standalone script compiled under tsconfig.scripts.json and does not import from apps/server/src; pulling in a server module for two lines is a bigger blast radius than the debt.

Liveness check (dead-site rule)

Each of the three enclosing functions was confirmed reachable from within its declaring file before the edit: validateStoredPin has 4 call sites in pin-write.ts (165, 181, 234, 252); runStep has 5 in plugin-status.ts (209, 225, 291, 355, 512); the whiteboard_update handler is registered under if (allowed.has("whiteboard_update") && context.updateWhiteboard) at line 284.

Validation

  • pnpm run check — clean (server, web, site).
  • pnpm run test — 186+128+9 files, 5227 tests, 0 failures (Postgres via repo_dev_up, TEST_DATABASE_URL/DATABASE_URL exported).
  • pnpm run test:e2e — 198 passed, 12 skipped.
  • No apps/web/ files changed, so finalize:web is not applicable.

Probe results, reported honestly. I probed each swept site by replacing the call with a constant and re-running its colocated suite:

  • whiteboard-tools.tsmcp-whiteboard-tools.test.ts fails (1 of 3). Covered.
  • pin-write.tspin-write.test.ts stayed green (36/36). Its tests exercise merge/label/id rejection paths; nothing drives validatePinValue into throwing through validateStoredPin, so the wrapper's message text is unasserted.
  • plugin-status.tsplugin-status.test.ts stayed green (20/20). Deliberate: runStep's raw text never reaches an assertion because the caller replaces it with a curated message ("Failed to refresh the dispatch marketplace.", "Failed to update the plugin." — lines 317, 335).

I did not add tests to close those gaps: the substitution is textually identical to the code it replaces, so a new test would assert the helper's behavior, not this diff's. Flagging the two coverage gaps as an observation rather than manufacturing coverage for a no-op change.

Next run

Queued: the complexity hotspot apps/web/src/components/app/chat/chat-entries.tsx (1180 lines, now the largest web component in the repo, landed across #1042#1056 and never audited).

🤖 Generated with Claude Code

…shared helper (#tech-debt)

`errorMessage` in apps/server/src/shared/lib/error-message.ts is literally
`error instanceof Error ? error.message : String(error)`. Three sites had
re-inlined that exact ternary since the last sweep (#914/#926):

- apps/server/src/agents/pin-write.ts:52
- apps/server/src/shared/plugin-status.ts:124
- apps/server/src/shared/mcp/whiteboard-tools.ts:338

Textually identity-preserving — no behavior change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@selfcontained
selfcontained merged commit 36fa211 into main Sep 9, 2026
1 check passed
@selfcontained
selfcontained deleted the tech-debt/error-message-sweep-1080 branch September 9, 2026 09:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant