Errors¶
How each SDK separates a business verdict from a programming or infrastructure failure.
OpenPit draws one line through its whole surface:
- A reject is an expected business outcome. A policy looked at the request and said no. Rejects are always returned as values, never raised, and they carry a stable reject code.
- An error is a failure of the call itself: invalid input, lifecycle misuse, an impossible configuration, or a boundary failure. Errors use whatever the language considers idiomatic - a returned error value, a raised exception, or a thrown object.
Handling code should branch on the first and let the second surface loudly. A reject is normal traffic; an error means the integration is wrong or the process is in trouble.
The reject record itself - its fields and their meaning - is described in Pre-trade Pipeline, and the code vocabulary in Reject Codes.
Go¶
Pipeline calls return three values: the handle, the rejects, and the error.
Policy rejects from the start stage, the main stage, and the evaluation failures from drop copy come back as the second value, a reject slice. A non-empty slice means the call produced no handle; an empty one means the stage passed. Drop copy ignores ordinary policy verdicts and returns only the failures that prevented historical bookkeeping.
Infrastructure failures and API misuse come back as the third value, an ordinary Go error:
- from a pipeline or post-trade call, a transport-level or lifecycle failure, never a business reject;
- from a policy builder, an invalid configuration.
Business rejects use the stable code constants exported by the reject package, for example the order-quantity-limit code when an order exceeds its configured cap.
Python¶
Rejects are returned on the result objects of the start stage, the main stage, and the account-adjustment batch. The result object is falsy when the stage did not pass, so a plain truth test is enough to branch.
Exceptions are reserved for invalid API usage and unexpected callback failures: a type error for a wrong wrapper type, a value error for an invalid domain value such as an empty asset, and a runtime error for lifecycle misuse such as executing the same request twice. Admin account-blocking calls raise their own dedicated exception.
Custom policies must not raise for a normal risk decision - return a policy reject instead.
The full Python exception surface, including the fields each exception carries, is documented in the Python errors guide.
JavaScript and TypeScript¶
Policy rejects from the start stage and the main stage are not exceptions:
they are returned on the result object, as an ok flag plus a rejects array.
Malformed JavaScript shapes throw a native TypeError. Invalid values and
numeric ranges throw RangeError subclasses such as ParamError,
AssetError, and AccountIdError, all rooted at OpenpitValueError.
Lifecycle and engine-state failures use named Error subclasses.
Every error OpenPit constructs at the boundary is also branded, so
instanceof OpenpitError remains the catch-all in both the Node and the
browser build. Branch on the native category, the concrete class, or the stable
err.name:
import { ParamError, OpenpitError } from "@openpit/engine";
import { Price } from "@openpit/engine/param";
try {
Price.fromString("not a number");
} catch (err) {
if (err instanceof ParamError) {
console.error(err.code); // e.g. "InvalidFormat"
} else if (err instanceof OpenpitError) {
console.error(err.name, err.message);
}
}
The base class and every subclass are exported from the root entry point;
AccountBlockError is also re-exported from the reject subpath. The subclasses
are:
ParamError- invalid numeric input, arithmetic overflow, or a malformed value.AssetError/AccountIdError- empty or invalid asset or account identifiers.LifecycleError- single-use misuse: executing the same request twice, finalizing the same reservation twice, using a stale account-control handle, reusing an engine builder that was already consumed, or re-entering an engine or one of its retained accounts or configuration facades from its own callback.InternalError- a defect inside the engine, reported instead of a bare WebAssembly trap. It poisons the loaded module instance: every later call that would reach core state returns this error instead of touching it, across the whole state-bearing surface. Discard every handle from that instance and reload the module.EngineBuildError- building an engine with no policy registered, or with a duplicate policy name or group id, or with an invalid built-in configuration.PolicyConfigureError- unknown policy, settings-type mismatch, rejected update, or a non-reentrant nested configuration call.PolicyCallbackError- a custom callback threw. Itscauseis the original thrown value, whatever its class;resultcarries the completed post-trade or account-adjustment result when that operation produces one. An operation abandoned by an engine defect reports the internal error instead.MarketDataError(withUnknownInstrumentandQuoteUnavailable),RegistrationError(withAlreadyRegisteredandUnknownInstrumentId),AccountGroupRegistrationError, andAccountBlockErrorfor the remaining market-data, registration, account-group, and admin-block failures.
Two stable code vocabularies appear on the JavaScript surface, and they do not overlap:
err.codeis set only onParamError,AssetError, andAccountIdError. It classifies a value failure - for example"InvalidFormat","Overflow","Negative", or"Other"when no finer code applies.ParamError.paramidentifies the affected value type andParamError.inputpreserves malformed text where the core reports it. The other subclasses leavecodeundefined.- A
kindfield tells apart the variants of one failure family.AccountBlockError.kindis"ReservedGroup","AccountNotBlocked", or"GroupNotBlocked". Registration, account-group, engine-build, and policy-configuration failures expose their own stablekindplus structured fields such as the instrument id, account id, policy name, policy group id, and the expected and found values, so callers never parse a human-readable message.
The reject code vocabulary is separate again: it is carried on a business reject and never on a thrown error.
C++¶
Expected business outcomes are returned as values:
- pre-trade rejects from the start stage, the main stage, and the shortcut call;
- account operation outcomes from the account-control and adjustment APIs.
Programmer mistakes, invalid input, lifecycle misuse, and runtime boundary
failures throw openpit::Error or a more specific derived type such as
openpit::EngineBuildError for an impossible engine configuration or
openpit::ConfigureError for a rejected runtime reconfiguration. Catching the
base type is enough for a generic handler; the derived types carry the
structured detail.
Rust¶
Both pipeline stages return a Result whose error side is the collected
rejects, so a reject is still a value rather than a panic: the start stage
yields a deferred request or the rejects, and the main stage yields a
reservation or the rejects.
Everything else is a dedicated error enum returned in a Result: engine
construction, runtime reconfiguration, value-type construction and checked
arithmetic, admin account blocking, account-group registration, and reference
book registration each have their own. Production code paths do not panic.
Related Pages¶
- Reject Codes: The stable business reject vocabulary and the evaluation-failure classifier
- Pre-trade Pipeline: The reject record and where each stage returns it
- Account Blocking: The mutation finalizer contract, where a failure has no caller to report to
- Policy API: How a custom policy reports a reject instead of failing the call