Optionalmessage: stringOptional human-readable reason (logged, not routed on)
Readonly__type__Runtime brand (Symbol.for — survives duplicated module instances)
Static OptionalprepareOptional override for formatting stack traces
OptionalstackStaticstackStaticcaptureCreate .stack property on a target object
OptionalconstructorOpt: FunctionStaticfromNominal constructor for a new OrderTransientError from any thrown object. Use this
instead of instanceof to recognize instances created by a DIFFERENT copy of
this module (duplicated bundles, linked packages).
Any thrown object
a new OrderTransientError with the original message, or a default message if the original was not a string
StaticisNominal type guard by the runtime brand. Provided for symmetry with OrderRejectedError / OrderDeletedError (e.g. for application-side logging) — the framework itself does not branch on it: transient is the default verdict for ANY non-typed throw.
Any thrown object
true when the object carries the OrderTransientError brand
EXPLICIT transient failure marker — "the operation failed for a temporary / unknown reason (network blip, lost response, exchange 5xx, rate limit); retry me".
Purpose: declarative sugar, not routing
The framework treats EVERY non-typed throw from the order gates and checks as the "transient" verdict already — this class adds NO special handling and is NOT pattern-matched anywhere in the framework by design. A plain
throw new Error(...)behaves identically. The class exists purely so application code states its intent explicitly: a reader of the adapter sees "transient" spelled out instead of having to know that unbranded throws default to it. Use it as the third leg of the triad:What the "transient" verdict means per channel
Resolved as
IBrokerOrderVerdict{ reason: "transient" }(see interfaces/Broker.interface):onOrderOpenCommittype "active"/"schedule",callbacks.onOrderSync,listenSync): the open is retried IDENTITY-STABLY — the same signal row with the SAME signalId is re-submitted on the next tick (event.attemptincrements; the attempt is PRE-ARMED — persisted before the gate call, so even a crash mid-attempt resumes with attempt >= 1), up to CC_ORDER_OPEN_RETRY_ATTEMPTS. Tag exchange orders withclientOrderId = signalIdand RECONCILE at attempt > 0: query the prior order by that id BEFORE re-sending and confirm the open if it filled. Do NOT rely on catching "duplicate" on re-send — Binance's duplicate-clientOrderId guard only covers OPEN orders; an instantly-filled market order will not dup. Exhaustion drops the signal loudly AND signalsexitEmitter(fatal: the network would not let the engine work). With the config at 0 the retry slot is disabled: a rejected open is dropped at once and the next tick regenerates a FRESH id.onOrderCloseCommit, same listeners): the position stays open and the close is re-attempted on the next tick/candle (event.attemptincrements), up to CC_ORDER_CLOSE_RETRY_ATTEMPTS. Exhaustion FORCE-CLOSES the engine state with the ORIGINAL closeReason +errorEmitter+exitEmitter(the real exchange position must be reconciled by the adapter/operator). With the config at 0 the cap is disabled: the close retries forever (legacy).onOrderActiveCheck/onOrderScheduleCheck,callbacks.onOrderCheck,listenCheck): the failed ping is TOLERATED — the order is assumed still open and monitoring continues (event.attemptincrements), up to CC_ORDER_CHECK_RETRY_ATTEMPTS CONSECUTIVE failures; a single successful check resets the streak to 0. Exhaustion acts terminally (close "closed" / cancel "user") +exitEmitter. With the config at 0 any failure is terminal on the spot (legacy).Nuances
exitEmitterafter theerrorEmitterlog) — unlike the typed terminal errors above, which are business outcomes and never signal a process exit.attempt > 0is therefore a HARD invariant even across crashes: a prior order MAY have reached the exchange — reconcile first. On restore the persisted counters are CLAMPED to 1: the reconcile bit survives, the streak resets — a pre-crash outage never exhausts the budget on the first post-restart attempt.__type__ === Symbol.for("OrderTransientError")and the static guard exist for consistency with the other two errors (useful in the application's own logging/metrics); the framework itself never checks it.Example