spend throws one of five errors. The table says whether your function ran.
All five carry
error.idempotencyKey. The manual calls authorize and charge do not throw. They
return a denial as a result and every other failure as { error }.
BudgetExceededError
A limit denied the estimate, and your function did not run. error.blocked names the limit and what
would let the same request through:
error.blocked also carries limitId, window, remaining, held, and resetsAt, and
error.balance holds the budget’s balance at the denial.
BudgetUnavailableError
Unprice could not be reached, or it answered 429 TOO_MANY_REQUESTS or 500
INTERNAL_SERVER_ERROR after the client’s retries. Your function did not run. The authorization
may still have committed, so retry with the same estimate, ttlMs, and error.idempotencyKey:
BudgetRecoveryError with reason: "authorization_replayed", the first
attempt committed and the work never ran. Run it and settle through error.hold, or release that
hold.
The default handle denies new work while Unprice is unreachable. In
local mode, spending continues within the lease until its deadline.
BudgetRequestError
The API rejected the authorization, for example because the budget does not exist (404), has closed
(409), or the request is invalid (400). Your function did not run. error.error holds the API
error with its code and requestId.
BudgetRecoveryError
The SDK cannot tell what the work used, so it keeps the hold and hands it to you as error.hold.
reason: "work_failed". Your function threw. The original error is error.cause. A provider
timeout can follow billable work, so check the provider’s result first. Settle known usage with
error.hold.settle({ amount }). Call error.hold.release() only after confirming the usage is
zero.
reason: "authorization_replayed". An authorization under your own idempotency key replayed,
so spend did not run your function again. Recover the provider’s result and settle through the
hold. A generated key never leaves the call, so its replay only means the client retried a lost
response, and spend runs the function.
The idempotency key protects budget accounting. It does not give exactly-once provider execution:
use the provider’s own idempotency, or a durable workflow, when the work must survive a crash.
BudgetSettleError
The work succeeded and produced error.value, but the settle failed. The first settle may have
committed, so do not rerun the work and do not record that usage.
- Transport failure (
error.cause): retryerror.hold.settle({ amount: error.actual }). - API error (
error.error): usage above the reserved maximum returns 409 and keeps the hold open. Reconcile the provider failure that let the work exceed its maximum. Do not clamp the amount or release the hold to hide the excess.
waitUntil, a failed background settle goes to onSettleError instead of
throwing. See settle in the background.