Error reporting — `see()`
The Kotlin SDK ships the see() structured-error surface (parity with @shipeasy/sdk and the Python reference). It reports a handled error along with its…
/docs/ — also served raw at https://shipeasy-ai.github.io/sdk-kotlin/pages/error-reporting.md.The Kotlin SDK ships the see() structured-error surface (parity with
@shipeasy/sdk and the Python reference). It reports a handled error along
with its product consequence — not just a stack trace — fire-and-forget to
/collect. Reporting never blocks and never throws into your request path.
If you don't know the consequence of an exception, don't catch it.
Package-level see()
see() reports against the SDK configured by configure() — no object to pass:
import ai.shipeasy.see
try {
chargeCard(order)
} catch (e: Exception) {
see(e)
.causesThe("checkout")
.to("use the backup processor", mapOf("order_id" to order.id))
}The chain:
causesThe(subject)— names the thing affected (the consequence subject).to(outcome, map)— terminal: builds the wire event and fires the report, with the extras folded in (String / finite Number / Boolean only; truncated, capped at 20 keys). If you never callto(), nothing is sent. Callingto()twice is a no-op.extras(map)— standalone setter for the same context; reach for it only when you genuinely cannot pass the context inline.
Where extras go in the chain
causesThe(subject) and to(outcome) are two halves of one sentence and must
stay adjacent, so fold the extras into the terminal:
// PREFERRED — the consequence reads as one sentence:
see(e).causesThe("checkout").to("use cached prices", mapOf("order_id" to order.id))to() returns Unit, so extras cannot trail the terminal in Kotlin. And never
split the sentence with extras():
// WON'T COMPILE — to() returns Unit:
// see(e).causesThe("checkout").to("use cached prices").extras(mapOf("order_id" to order.id))
// WRONG — extras wedged between the subject and the outcome. You read
// "checkout … order_id … use cached prices" and lose the consequence.
// see(e).causesThe("checkout").extras(mapOf("order_id" to order.id)).to("use cached prices")Non-exception problems — seeViolation
The name is a stable fingerprint key — put variable data in extras(), never
in the name:
import ai.shipeasy.seeViolation
seeViolation("negative_inventory")
.to("clamp to zero", mapOf("sku" to sku))Expected control flow — controlFlowException
Mark an exception as expected control flow; it reports nothing. .extras()
is stored for local debugging only.
import ai.shipeasy.controlFlowException
controlFlowException(e).because("retryable timeout — handled by the retry loop")Notes
- A per-process spam guard collapses identical reports within a 30s window and caps total sends per process.
- Configured
privateAttributesare stripped fromextras(). env(fromconfigure()) is tagged onto every event.- Calling
see()beforeconfigure()ran logs a warning and is a no-op.
Kill switches
getKillswitch(name) returns a Boolean: true when the kill switch is killed (the feature should be turned OFF). Kill switches ride in the same flags blob as…
Testing
Two configure() siblings let your tests evaluate without ever touching the network — both REPLACE any prior configuration (unlike configure()'s…