Xử lý lỗi
Hệ thống exception và cách xử lý lỗi trong Python SDK
SDK sử dụng hệ thống exception phân cấp:
Danh sách exception
| Exception | Mô tả |
|---|---|
SSIError | Base exception — có message, code, status_code, response_body, headers |
AuthenticationError | Xác thực thất bại (sai credentials, token hết hạn) |
SmartOTPPendingError | Con của AuthenticationError. Smart OTP chưa được duyệt trên thiết bị (HTTP 202 / 401114) hoặc hết thời gian chờ polling. Gọi lại ensure_authenticated(transaction_id=...) với cùng transaction_id |
SmartOTPRejectedError | Con của AuthenticationError. Smart OTP bị từ chối, hết hạn hoặc không tìm thấy giao dịch (401113, 401115, 401116). SDK dừng ngay, không polling tiếp |
ReauthenticationRequired | Con của AuthenticationError. Không thể refresh token, hoặc server từ chối refresh (401101, 401103). SDK xoá token đang giữ và không retry; cần xác thực lại bằng OTP mới |
APIError | API trả về lỗi — code là mã lỗi của server (hoặc HTTP status dạng chuỗi), kèm status_code, response_body |
DuplicateRequestError | Con của APIError. HTTP 409: clientRequestId / batchRequestId đã được dùng trong ngày. SDK không tự gửi lại lệnh với id mới vì lệnh gốc có thể đang hoạt động |
WebSocketError | Lỗi kết nối hoặc giao tiếp WebSocket |
TradingWSError | Con của WebSocketError. Frame lỗi từ Trading WebSocket — có status, error_code, server_message. Xem Trading WebSocket |
ValidationError | Lỗi validate input (kiểm tra phía SDK, trước khi gửi request) |
RateLimitError | Vượt quá giới hạn request — có thêm status_code, retry_after_ms, limit, remaining, reset |
Chuỗi kế thừa
Exception → SSIError → AuthenticationError → SmartOTPPendingError
→ SmartOTPRejectedError
→ ReauthenticationRequired
Exception → SSIError → APIError → DuplicateRequestError
Exception → SSIError → WebSocketError → TradingWSError
Exception → SSIError → ValidationError
Exception → SSIError → RateLimitErrorSử dụng cơ bản
from ssi_sdk import SSIError
try:
auth.authenticate(otp="<OTP>")
except SSIError as e:
print(f"Lỗi: {e.message} (code: {e.code})")Xử lý chi tiết theo loại lỗi
from ssi_sdk.exceptions import (
APIError,
AuthenticationError,
DuplicateRequestError,
RateLimitError,
)
from ssi_sdk.enums import OrderSide
try:
result = trading.trading.place_limit_order(
account_no="<ACCOUNT_NO>",
symbol="SSI",
side=OrderSide.BUY,
quantity=100,
price=68000,
)
except AuthenticationError:
print("Cần xác thực lại")
except RateLimitError as e:
print(f"Rate limited, retry sau {e.retry_after_ms} ms")
except DuplicateRequestError:
print("client_request_id đã dùng trong ngày, không gửi lại")
except APIError as e:
print(f"API error {e.status_code} (code {e.code}): {e.message}")DuplicateRequestError là con của APIError, nên phải bắt nó trước APIError.
Smart OTP và xác thực lại
from ssi_sdk.exceptions import (
ReauthenticationRequired,
SmartOTPPendingError,
SmartOTPRejectedError,
)
otp = auth.request_otp_typed() # OTPResponse(message, transaction_id)
try:
auth.ensure_authenticated(transaction_id=otp.transaction_id)
except SmartOTPPendingError:
# Chưa duyệt kịp: gọi lại với cùng transaction_id
auth.ensure_authenticated(transaction_id=otp.transaction_id)
except SmartOTPRejectedError:
print("Smart OTP bị từ chối hoặc hết hạn, yêu cầu OTP mới")
except ReauthenticationRequired:
print("Phiên không refresh được, cần xác thực lại bằng OTP mới")- Mỗi
apiKeychỉ có 1 phiên hoạt động. Khi dùng lại refresh token, server thu hồi mọi phiên củaapiKeyđó (401103). ReauthenticationRequiredkhông bao giờ được retry tự động.
RateLimitError
retry_after_mslà mili-giây (SDK đổi từ headerRetry-Aftertính bằng giây).limitvàremaininglấy từ headerX-RateLimit-Limit/X-RateLimit-Remainingnếu server gửi.resetthường làNonevì server không gửi thời điểm reset.
ServerErrorCode
ssi_sdk.enums.ServerErrorCode liệt kê các mã lỗi ứng dụng mà server trả trong {"code", "msg"} (ví dụ OTP_VERIFICATION_FAILED = 401100, REFRESH_TOKEN_REVOKED_OR_EXPIRED = 401103, PUSH_APPROVAL_REJECTED = 401115, MODIFY_PRICE_AND_QUANTITY = 400107, REPLAY_WINDOW_EXCEEDED = 400111, TIMEFRAME_NOT_SUPPORTED = 400210). Một số số được dùng lại cho nhiều ý nghĩa (ví dụ 400104 vừa là "không gửi được OTP" vừa là "thiếu symbol"), nên tên sau là alias của tên đầu. Các mã chữ ký (4010xx) không khớp hoàn toàn với error-code-mapping.json phía server: hãy tin số mã, không tin text đã map.
from ssi_sdk.enums import ServerErrorCode
try:
...
except APIError as e:
if ServerErrorCode.from_value(e.code) == ServerErrorCode.REPLAY_WINDOW_EXCEEDED:
print("Request nằm ngoài cửa sổ thời gian cho phép")from_value trả về None với mã không có trong enum, nên không bao giờ raise. HTTPStatus (cùng module) là IntEnum các HTTP status mà API dùng (có is_auth_error, is_rate_limit, is_client_error, is_server_error).
Gợi ý xử lý
- Bắt
SSIErrorở lớp ngoài cùng để gom lỗi chung. - Bắt
AuthenticationErrorkhi cần refresh token hoặc yêu cầu OTP mới; bắt các lớp con (SmartOTPPendingError,SmartOTPRejectedError,ReauthenticationRequired) trước nếu cần xử lý riêng. - Bắt
RateLimitErrorvà tôn trọngretry_after_msđể backoff. - Bắt
APIErrorđể xử lý lỗi nghiệp vụ từ server. HTTP 200 kèmcodekhác 200/204 cũng được ném thànhAPIError. - Chỉ request GET được SDK tự retry; POST/PUT/DELETE (đặt lệnh, huỷ lệnh, batch) không bao giờ bị retry tự động.
- Lỗi từng lệnh trong batch order là dữ liệu trong
BatchOrderResult, không phải exception. Xem Batch Order. - Bắt
WebSocketErrorkhi xử lý streaming; Trading WebSocket némTradingWSError. - Bắt
ValidationErrorkhi cần xác thực input trước khi gọi API.