Drift
When a server error payload for an ORDER_NOT_FOUND/MARKET_NOT_FOUND/EVENT_NOT_FOUND code already contains a fully-formatted message (e.g. "Order not found: 123"), TypeScript's fromServerError passes that message straight into the matching subclass's constructor, which treats its first argument as a bare identifier and unconditionally re-wraps it with the same prefix — producing a doubled message like "Order not found: Order not found: 123". Python's from_server_error reconstructs the message through the same path but explicitly guards against this via _format_not_found_message, which is a no-op if the identifier already starts with the target prefix.
TypeScript SDK
sdks/typescript/pmxt/errors.ts:165-166 (fromServerError, generic branch): for any mapped error class other than RateLimitExceeded/ValidationError, it calls:
return new ErrorClass(message, exchange);
For code === "ORDER_NOT_FOUND", ErrorClass is OrderNotFound (errors.ts:57-61):
export class OrderNotFound extends NotFoundError {
constructor(orderId: string, exchange?: string) {
super(`Order not found: ${orderId}`, exchange, "ORDER_NOT_FOUND");
}
}
message (the already-formatted server string) is passed positionally as orderId and unconditionally re-wrapped in `Order not found: ${orderId}`. The same pattern exists for MarketNotFound (errors.ts:63-67) and EventNotFound (errors.ts:69-73) — none guard against an already-prefixed input.
Python SDK
sdks/python/pmxt/errors.py:169 (from_server_error) calls error_class(message, **kwargs) the same way, landing on OrderNotFound.__init__ (errors.py:58-63):
def __init__(self, order_id: str, exchange: str | None = None, **_ignored: Any):
super().__init__(
_format_not_found_message("Order not found: ", order_id),
code="ORDER_NOT_FOUND",
exchange=exchange,
)
_format_not_found_message (errors.py:32-33) checks identifier.startswith(prefix) and returns it unchanged if so, avoiding the double prefix. MarketNotFound (errors.py:66-73) and EventNotFound (errors.py:76-83) use the same guarded helper.
Expected
A server error payload like {"code": "ORDER_NOT_FOUND", "message": "Order not found: 123"} round-tripped through fromServerError/from_server_error should produce the same .message in both SDKs. Either both should guard against re-prefixing (matching Python's current behavior), or neither should.
Impact
Any hosted-mode or sidecar error response for a not-found condition gets its message doubled in the TypeScript SDK ("Order not found: Order not found: 123") but not in Python, producing inconsistent, confusing error text surfaced to end users/logs depending on which SDK is used against the identical server response.
Found by automated SDK cross-language drift audit
Drift
When a server error payload for an
ORDER_NOT_FOUND/MARKET_NOT_FOUND/EVENT_NOT_FOUNDcode already contains a fully-formatted message (e.g."Order not found: 123"), TypeScript'sfromServerErrorpasses that message straight into the matching subclass's constructor, which treats its first argument as a bare identifier and unconditionally re-wraps it with the same prefix — producing a doubled message like"Order not found: Order not found: 123". Python'sfrom_server_errorreconstructs the message through the same path but explicitly guards against this via_format_not_found_message, which is a no-op if the identifier already starts with the target prefix.TypeScript SDK
sdks/typescript/pmxt/errors.ts:165-166(fromServerError, generic branch): for any mapped error class other thanRateLimitExceeded/ValidationError, it calls:For
code === "ORDER_NOT_FOUND",ErrorClassisOrderNotFound(errors.ts:57-61):message(the already-formatted server string) is passed positionally asorderIdand unconditionally re-wrapped in`Order not found: ${orderId}`. The same pattern exists forMarketNotFound(errors.ts:63-67) andEventNotFound(errors.ts:69-73) — none guard against an already-prefixed input.Python SDK
sdks/python/pmxt/errors.py:169(from_server_error) callserror_class(message, **kwargs)the same way, landing onOrderNotFound.__init__(errors.py:58-63):_format_not_found_message(errors.py:32-33) checksidentifier.startswith(prefix)and returns it unchanged if so, avoiding the double prefix.MarketNotFound(errors.py:66-73) andEventNotFound(errors.py:76-83) use the same guarded helper.Expected
A server error payload like
{"code": "ORDER_NOT_FOUND", "message": "Order not found: 123"}round-tripped throughfromServerError/from_server_errorshould produce the same.messagein both SDKs. Either both should guard against re-prefixing (matching Python's current behavior), or neither should.Impact
Any hosted-mode or sidecar error response for a not-found condition gets its message doubled in the TypeScript SDK (
"Order not found: Order not found: 123") but not in Python, producing inconsistent, confusing error text surfaced to end users/logs depending on which SDK is used against the identical server response.Found by automated SDK cross-language drift audit