Skip to main content
A send either returns a SendResult or throws a RepostException subclass that tells you exactly what happened and whether the event may already have reached Repost. This page covers the outcome model end to end.

Idempotency

Repost dedupes on the idempotency key. When you don’t pass one, the runtime mints a stable key per operation and reuses it across every internal retry, so a flaky connection cannot produce a duplicate. That minted key protects only the retries inside that one call. To make repeats safe across process restarts and queue redeliveries, pass your own key naming the business fact:
The server remembers caller-supplied keys for 24 hours; a repeat with the same payload returns the original message, and a repeat with a different payload is rejected. The details are on the HTTP API page.

Delivery outcomes

Every failure is a RepostException carrying a stable ErrorCode, a best-known DeliveryState, the IdempotencyKey, the started AttemptCount, and a Retryable flag — never a raw server body, header, or nested exception. The five delivery states:
The exception subclass tells you the category without inspecting a code: RepostConfigurationException (bad config), RepostValidationException (your model failed validation, NotSent), RepostSerializationException, RepostTransportException (connect/TLS/timeout/cancel/overload), RepostPublishException (the server rejected the request or returned a retryable failure), and RepostDescriptorVersionException (regenerate or upgrade — the generated client and runtime are incompatible).

What retries automatically

Up to three retries follow the initial attempt (four attempts total by default). Retryable outcomes include DNS, connect, proxy, TLS, and I/O failures, an attempt timeout, 5xx, 429, 409, and a malformed 2xx body. Any other 4xx (400, 401, 403, 413, …) is thrown immediately. Backoff is full jitter in integer milliseconds from zero through min(60_000, RetryBaseDelay × 2^(attempt−1)); a valid Retry-After delta or HTTP-date raises that delay, still capped at 60 seconds. Each attempt gets a fresh timeout budget; the whole operation is bounded by OperationTimeout. A payload over 1 MiB is rejected before the first attempt with a RepostSerializationException (RequestTooLarge), so an oversized event never reaches the network.

Cancellation

Every send method takes an optional CancellationToken. Cancelling before the request commits settles NotSent; cancelling after it may have been written settles CancelledUnknown — reconcile with the same key. Either way the operation settles exactly once and closes only the work it owns.

Bounded admission

MaxInFlightOperations is a hard bulkhead, not a queue. When more operations are in flight than the budget allows, a new send is rejected immediately with a RepostTransportException whose ErrorCode is Overloaded and DeliveryState is NotSent — the runtime never buffers unbounded work or paces your traffic. Treat it as backpressure and retry with the same key.

What goes on the wire

Payloads serialize deterministically: model fields in schema declaration order under their wire names, absent optional fields omitted (or their @default injected), explicit null only where the schema allows it, and timestamps in the ISO-8601 millisecond UTC form. Unknown input properties are dropped, and a value you provide is never overridden by a default.

Continue

Testing

Exercise these paths without a network.

Configuration

The transport options behind the retry behavior.

Delivery & retries

What happens to the message once Repost accepts it.