Transient Retry
client.commit.apply(...) and OperationBuilder.commit(...) automatically retry some ambiguous first-chunk failures: timeouts, dropped connections, and server 5xx responses on the very first stream append, where no operation has been acknowledged yet.
In plain terms: simple single-op writes retry automatically; multi-op writes and writes using advanced stream options surface ambiguous failures as PartialStreamSubmissionError. If the backend deterministically rejects every submitted operation, the SDK throws AllStreamOperationsFailedError with the per-op failure ledger on error.result and error.operations.
Auto-retry is conservative — it only fires when every condition holds:
- The first chunk contains exactly one operation (multi-op chunks are rejected because the backend applies each op in its own transaction; a mid-chunk failure may have committed an arbitrary prefix).
- No operation in the chunk references
$N/#Nallocation tokens (a freshstreamIdon retry would resolve those tokens to a different identity than the first attempt may have landed). - No
streamIdor non-emptyallocatedTokenswas supplied (manual-resume mode bypasses retry).
When auto-retry fires, the SDK mints a fresh streamId and re-issues the operation. The retry does not prove the original attempt did not land — definite rejections on the retry are wrapped as PartialStreamSubmissionError so the “inspect repo state before continuing” guarantee survives. Callers needing safe retry should make add operations idempotent with skipExisting: true — pass it via client.commit.apply’s options or set it on each OperationBuilder.add(...) op directly.
For callers, a successful retry behaves like a single successful submission: the method resolves with the server’s operation results.
Tuning Retry
Section titled “Tuning Retry”Pass retry: false to disable automatic retry:
await client.commit.apply(org, repo, message, operations, { retry: false })Pass a RetryPolicyOptions value to override defaults:
await client.commit.apply(org, repo, message, operations, { retry: { maxAttempts: 4, baseDelayMs: 100, maxDelayMs: 1000, },})OperationBuilder.commit(...) accepts the same retry option.
Partial Submissions
Section titled “Partial Submissions”The SDK throws PartialStreamSubmissionError whenever an ambiguous or partial append outcome cannot be reduced to a clean success or definite failure. This covers both:
- Mid-stream failures. A multi-chunk submission whose first chunks acknowledged but a later chunk failed ambiguously.
completedOperationslists the operations the SDK knows landed. - First-chunk ineligible-for-retry failures. The first append fails ambiguously, but auto-retry is disabled (
retry: false) or ineligible (multi-op first chunk, token-using ops, or manual-resume mode).completedOperationsis empty, but the failed append may still have landed server-side.
In every case, the failed append may have landed server-side, so inspect repository state before submitting additional operations.
Definite request-level rejections propagate as WarmHubError with the original kind and code. Examples include UNAUTHENTICATED, FORBIDDEN, VALIDATION_ERROR, RATE_LIMITED, and UNRESOLVED_TOKEN. Definite operation-level rejections can also resolve as mixed partial results; when every operation is rejected, they throw AllStreamOperationsFailedError so callers can still inspect each failed op.
Practical Rule
Section titled “Practical Rule”Retry automatically when the SDK returns success or when a normal retryable WarmHubError is safe for your workload. When you catch PartialStreamSubmissionError, treat repository state as the source of truth before deciding what to submit next. When you catch AllStreamOperationsFailedError, use error.operations to fix the rejected inputs before retrying.
Hit a problem or have a question? Get in touch.