Shipeasy
ReferenceTypeScript / JavaScript

Error reporting (`see()`)

see (shipeasy error) is the structured error reporter. Every handled exception documents its product consequence, not just its stack. It works in vanilla JS…

Generated from the SDK's own /docs/ — also served raw at https://shipeasy-ai.github.io/sdk/pages/error-reporting.md.

see (shipeasy error) is the structured error reporter. Every handled exception documents its product consequence, not just its stack. It works in vanilla JS on both sides — the whole grammar hangs off one import:

import { see } from "@shipeasy/sdk/client"; // or "@shipeasy/sdk/server"

Report a handled exception — see(e)

try {
  await submitOrder(order);
} catch (e) {
  see(e).causes_the("checkout").to("use cached prices").extras({ order_id: order.id });
}

The chain dispatches on the next microtask — no .send(). It ships immediately (sendBeacon in the browser, fire-and-forget fetch on the server), spam-guarded by a 30s dedup window and a per-session cap.

Report a non-exception problem — see.Violation(name)

The name is a stable identifier (it participates in the issue fingerprint), so put variable data in .extras(), never the name:

if (rows.length > LIMIT) {
  see
    .Violation("large query")
    .causes_the("search results")
    .to("be trimmed")
    .extras({ rows: rows.length });
}

Never use see.Violation() for a caught exception — you'd drop the stack. Pass the caught Error to see() instead.

Mark expected control flow — see.ControlFlowException(e)

Document an expected exception and report nothing (auto-capture skips marked errors). The reason must start with "because":

try {
  return decodeFoo(blob);
} catch (e) {
  see.ControlFlowException(e).because("because it wasn't an encoded Foo");
  return decodeBar(blob);
}

Where reports land

The Shipeasy errors primitive — fingerprint-grouped issues (open / resolved / ignored, regression auto-reopens) with a near-real-time occurrence timeseries.

Client auto-capture

The client SDK also auto-captures network failures (fetch network errors + 5xx) into the same primitive (autoCollect: { errors }, on by default) — each names a specific endpoint and outcome. It deliberately does not blanket- report uncaught exceptions or unhandled promise rejections (those carry no actionable consequence). Code that knows the consequence reports it explicitly.

Rules

  • If you don't know the consequence, don't catch the exception.
  • You may see() then re-throw — the re-thrown error links to its inner report as a caused_by chain instead of double-counting.
  • Never put PII or high-cardinality data in extras.
  • A see() call before configure() / shipeasy() warns and drops — it never throws.
Was this page helpful?
✎ Edit this page

On this page