Errors and diagnostics
Softchat failures are stable, typed, and redacted. Rust uses enum variants; the authored facades expose one idiomatic error value with one stable code. Branch on that variant or code, never display text, a generated-binding exception, relay prose, or an upstream cryptographic error.
The Android account runtime also emits optional structured diagnostics with
English summaries, TX/RX direction, authenticated subject, source timestamps,
and bounded counters. The account logging contract
defines the event catalog, committed milestones, privacy rules, and volume limits.
Logs support diagnosis; commands and queries remain the source of product state.
Handling failures
errors.handlingHandle stable redacted failures without generated-binding leakage.
- Inputs and exact bounds
- one SDK operation failure
- Output
- One idiomatic error value and stable code.
- Trust and authentication
- Display text is safe but not a branching contract.
- Stable errors
internal_failure· handling and retry rules
Ownership, lifecycle, and execution rules
- Ownership
- Rust owns protocol semantics, Android account SQLite/use-case state, and optional native relay I/O; the host owns account lifecycle, HTTP/media/background effects, files, and UI.
- Retry
- Retry only host transport or explicitly retryable session work; validation and authentication failures are permanent for the same input.
- Lifecycle
- Language ownership is automatic; explicitly cancel or erase only at the operation-specific authority boundary.
- Concurrency
- Serialize mutable session capabilities; immutable values follow the language type system.
- Cancellation
- The host owns async cancellation; use cancel, shutdown, close, or erase only where exposed.
Exact public symbols
- Rust
- Android
- Swift
- TypeScript
SoftchatErrorSoftchatExceptionSoftchatErrorCodeSoftchatErrorSoftchatErrorSoftchatErrorCode- Rust
- Android
- Swift
- TypeScript
match bob.decrypt_utf8(&message) {
Ok(plaintext) => display(plaintext),
Err(SoftchatError::DecryptionFailed) => discard_untrusted_message(),
Err(SoftchatError::IdentityErased) => require_reauthentication(),
Err(error) => record_code(error.code()),
}
try {
display(identity.decrypt(message))
} catch (error: SoftchatException) {
when (error.code) {
SoftchatErrorCode.DECRYPTION_FAILED -> discardUntrustedMessage()
SoftchatErrorCode.IDENTITY_ERASED -> requireReauthentication()
else -> recordCode(error.code)
}
}
Map stable SoftchatException.code values into domain failures before they
reach UI. Do not include input payloads in Crashlytics breadcrumbs or
WorkManager output data.
do {
display(try identity.decrypt(message))
} catch let error as SoftchatError where error.code == .decryptionFailed {
discardUntrustedMessage()
} catch let error as SoftchatError where error.code == .identityErased {
requireReauthentication()
}
try {
display(identity.decrypt(message));
} catch (error) {
if (error instanceof SoftchatError && error.code === "decryption_failed") {
discardUntrustedMessage();
} else {
throw error;
}
}
Retry categories
| Failure | Typical action |
|---|---|
| malformed, invalid, oversized, unsupported | permanent rejection of that input |
| authentication/decryption failure | discard untrusted value; do not reveal details |
| erased/closed/cancelled state | create a new authority or state object when policy permits |
relay retryable delivery | persist and retry under the session’s requested policy |
| internal failure | record only build fingerprint, stable code, and safe host context |
Build fingerprint
diagnostics.snapshotIdentify the loaded artifact and inspect redacted counters.
- Inputs and exact bounds
- no protocol payload input
- Output
- Build fingerprint and monotonic redacted counters.
- Trust and authentication
- Diagnostics contain no keys, plaintext, ciphertext, or event contents.
- Stable errors
internal_failure· handling and retry rules
Ownership, lifecycle, and execution rules
- Ownership
- Rust owns protocol semantics, Android account SQLite/use-case state, and optional native relay I/O; the host owns account lifecycle, HTTP/media/background effects, files, and UI.
- Retry
- Retry only host transport or explicitly retryable session work; validation and authentication failures are permanent for the same input.
- Lifecycle
- Language ownership is automatic; explicitly cancel or erase only at the operation-specific authority boundary.
- Concurrency
- Serialize mutable session capabilities; immutable values follow the language type system.
- Cancellation
- The host owns async cancellation; use cancel, shutdown, close, or erase only where exposed.
Exact public symbols
- Rust
- Android
- Swift
- TypeScript
build_fingerprintdiagnostics_snapshotSoftchat.buildFingerprintSoftchat.diagnosticsSnapshotsoftchatBuildFingerprintsoftchatDiagnosticsSnapshotbuildFingerprintdiagnosticsSnapshotThe build fingerprint identifies the semantic version, source revision, protocol profile, target architecture, and target operating system. Include it with a bug report to distinguish package skew without logging account data.
- Rust
- Android
- Swift
- TypeScript
let fingerprint = build_fingerprint();
val fingerprint = Softchat.buildFingerprint
let fingerprint = softchatBuildFingerprint
const fingerprint = buildFingerprint(); // after Wasm initialization
Diagnostics snapshot
The process-local snapshot reports aggregate operation counts, rejected operations, and input/output bytes. It deliberately excludes keys, plaintext, ciphertext, URLs, relay frames, event content, and identifiers.
- Rust
- Android
- Swift
- TypeScript
let counters = diagnostics_snapshot();
val counters = Softchat.diagnosticsSnapshot()
Sample only under the application’s telemetry consent policy.
let counters = softchatDiagnosticsSnapshot()
const counters = diagnosticsSnapshot();
Diagnostics are counters, not an audit trail. If an application needs operation correlation, generate its own non-secret trace ID outside the SDK.