Sloth-ninja puts a proper firewall between failures and client screens

A production incident exposed a familiar legal-tech risk: useful diagnostics vanished from logs while raw provider errors could still reach users.

securityinfrastructure

Sloth-ninja has tightened how this fork handles database and integration failures across core areas such as login, chat, matters, documents, reviews, workflows and account settings.

The new approach keeps enough redacted diagnostic detail in server logs for the team to investigate real outages, including errors returned in an awkward format by Supabase, the hosted database platform. But browsers now receive a consistent, non-revealing message instead of internal database, provider or configuration details. The work also preserves specific feedback where users genuinely need it, such as validation and selected live chat errors, and adds tests for both sides of the boundary.

So what Legal teams and product owners handling sensitive matters should care because clearer incident diagnosis no longer has to mean exposing operational detail to end users.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

4 commits from Sloth-ninja/JessicaOSS, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
28f4eb0c Error-visibility hardening: surface Supabase errors, stop raw-detail leaks sloth-ninja 2026-08-04 ↗ GitHub
commit body
Production incident 04/08/2026: real Supabase errors were invisible.
safeErrorLog/safeErrorMessage flattened PostgrestError plain objects to
the literal "Unexpected error", and 56 route/middleware sites sent the
raw DB/provider error message to the browser while logging nothing
server-side.

- safeError.ts: extract message/code/details/hint from non-Error
  message-bearing objects (known string fields only, always redacted);
  new GENERIC_ERROR_DETAIL constant and failRequest() helper (log
  redacted server-side + fixed generic client detail).
- asyncHandler.ts: use the shared constant.
- middleware/auth.ts: failure paths now console.error (devLog was
  dev-only, so production logged nothing); fixed 401/500 details.
- routes/{chat,projects,documents,tabular,workflows,user}.ts: every
  DB/provider-originated `detail: error.message` send converted to
  failRequest; user.ts 500-status errorMessage catches now log via
  safeErrorLog and send the fixed generic detail.
- New lib/safeError.test.ts: 17 tests pinning extraction, redaction,
  fallbacks and failRequest behaviour.

Hand-written validation details, multer 400s, MCP-connector actionable
errors and redacted SSE stream events left unchanged by design.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
5047ffb7 Review fixes: log-only extraction, harden errorMessage(), redact code, quiet 42703 sloth-ninja 2026-08-04 ↗ GitHub
commit body
- safeErrorMessage: revert the object-message widening - extraction is
  LOG-ONLY (all call sites are client-facing SSE/persisted text and libs
  rethrow raw Supabase plain objects); non-Error objects keep the fallback.
  safeErrorLog extracts independently, unchanged.
- routes/user.ts errorMessage(): Error instances keep their actionable
  message (redacted, string code appended); plain objects/strings degrade
  to GENERIC_ERROR_DETAIL - never join details/hint, never JSON.stringify.
  Fixes raw Postgrest text leaking through the MCP-connector 400/404
  sites. Exported for tests; follow-up: retire in favour of safeError.
- safeErrorLog: redact the code field before using it as name.
- middleware/auth.ts: 42703 (pre-migration, tolerated) stays at devLog;
  console.error only for real failures.
- Tests updated/added: safeErrorMessage fallback contract, code
  redaction, errorMessage both shapes (623 total).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2eca1c36 Re-review fixes: unblind errorMessage log sites, log tool-loop originals sloth-ninja 2026-08-04 ↗ GitHub
commit body
- user.ts: all 11 sites that passed errorMessage(err) to console.error now
  log safeErrorLog(err) - wave 2 had made plain-object errors log the
  literal generic sentence, strictly worse than main on the log side.
  errorMessage(err) remains only for the client detail at the seven split
  sites.
- errorMessage(): drop the "(code)" suffix entirely - it duplicated the
  sibling code field in user-visible copy on the oauth_required 401, and
  no other caller needs it.
- chatTools.ts tool-loop catch: console.error the ORIGINAL error via
  safeErrorLog before the AssistantStreamError rethrow, so Postgrest
  objects thrown by tools are visible in production logs.
- Tests: new route-level test (GET /user/api-keys) asserting the log
  receives extracted Postgrest diagnostics while the client gets the
  fixed detail; errorMessage suffix expectation updated. 624 total.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
d89f394b Merge remote-tracking branch 'origin/main' into error-visibility-hardening sloth-ninja 2026-08-04 ↗ GitHub
# Conflicts:
#	docs/BUILD_LOG.md

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-1064.md from inside the repo you want the changes in.

⬇ Download capture-thread-1064.md