Skip to content

Error handling

All library exceptions inherit from StoneXError, so a single except StoneXError catches everything stonepy can raise. Catch the more specific subclasses when you need to react to a particular failure.

from stonepy import (
    ClientConfig,
    ConfigurationError,
    OrderStatusUnknownError,
    RateLimitError,
    StoneXAPIError,
    StoneXClient,
    StoneXError,
)
from stonepy.models import ApiLogOnRequestDTO

config = ClientConfig(base_url="https://ciapi.cityindex.com/TradingAPI")

try:
    with StoneXClient(config) as client:
        client.session.log_on(
            ApiLogOnRequestDTO(
                UserName="username",
                Password="password",
                AppKey="app-key",
                AppVersion="stonepy",
                AppComments="",
            )
        )
except RateLimitError as exc:
    print(exc.retry_after)
except OrderStatusUnknownError as exc:
    # Do not blindly retry: the original write may have succeeded.
    print(exc.status, "verify the order state before resubmitting")
except StoneXAPIError as exc:
    print(exc.http_status, exc.error_code, exc.error_message)
except StoneXError as exc:
    print(exc)

Exception hierarchy

Exception Raised when
AuthenticationError Log-on failed or the session could not be refreshed.
ConfigurationError The client has no credentials configured for session refresh.
RateLimitError The API returned a rate-limit response; inspect retry_after.
OrderRejectedError The request was accepted but the order was rejected.
OrderStatusUnknownError A write acknowledgement could not be interpreted; the order may or may not have been placed.
StoneXAPIError A non-success API response; exposes http_status, error_code, error_message.
ResponseParseError The response body did not match the expected schema.
TransportError The request never completed (connection or timeout error).

See the Errors API reference for the full signatures.

Rejection semantics

A successful HTTP response is not always a successful order. For endpoints that acknowledge a write, stonepy uses the endpoint's documented status domain:

Domain Rejection behavior
Instruction Top-level InstructionStatus RedCard (2) and Error (4) raise OrderRejectedError. Accepted (1), YellowCard (3), and Pending (5) return the response. A yellow card is awaiting dealer approval and must not be treated as permission to resubmit.
Order OrderStatus Rejected (5) and RedCard (10) raise. Other lifecycle values, including unknown numeric values, are informational. Simulation responses use this domain.
Execution text save_order accepts Success, raises OrderRejectedError for Failure, and raises OrderStatusUnknownError for every other supplied text or numeric status. Matching ignores case and surrounding whitespace.

After an instruction acknowledgement passes, stonepy also checks each Orders[] item using the order domain. Fixed-margin responses expose the same two layers as InstructionStatusId/InstructionStatusReasonId and OrderStatusId/OrderStatusReasonId. Nested quote statuses are not interpreted.

Read endpoints do not run rejection checks. Their status fields describe stored current or historical state, so a returned Rejected order is data rather than a failed read.

OrderStatusUnknownError is intentionally not a subclass of OrderRejectedError. It means the acknowledgement for a non-idempotent write was unreadable, so the order may or may not have been placed. Inspect the attached response, query the order state, and reconcile by request/order identifier before resubmitting. A handler that automatically retries OrderRejectedError will therefore never catch this indeterminate case.