Skip to content

SDK drift: Python error subclasses (BadRequest, AuthenticationError, PermissionDenied, NotFoundError, InvalidOrder, InsufficientFunds) default .code to "UNKNOWN_ERROR" instead of their named code #1528

Description

@realfishsam

Drift

In TypeScript, every PmxtError subclass hardcodes its own .code in its constructor. In Python, most subclasses have no __init__ override at all, so they silently inherit PmxtError.__init__'s code: str = "UNKNOWN_ERROR" default instead of carrying their named code. This is the same root-cause pattern as already-filed #1422 (which covers only NotSupported), but affects a wider, actively-used set of classes: BadRequest, AuthenticationError, PermissionDenied, NotFoundError, InvalidOrder, and InsufficientFunds.

TypeScript SDK

sdks/typescript/pmxt/errors.ts:84-93:

export class InvalidOrder extends PmxtError {
    constructor(message: string, exchange?: string) {
        super(message, "INVALID_ORDER", false, exchange);
    }
}
export class InsufficientFunds extends PmxtError {
    constructor(message: string, exchange?: string) {
        super(message, "INSUFFICIENT_FUNDS", false, exchange);
    }
}

Same hardcoded-code pattern for BadRequest (line 33-37, "BAD_REQUEST"), AuthenticationError (line 39-43, "AUTHENTICATION_ERROR"), PermissionDenied (line 45-49, "PERMISSION_DENIED"), NotFoundError (line 51-55, "NOT_FOUND" default).

Python SDK

sdks/python/pmxt/errors.py:36-53, 94-102 — no __init__ override on any of these:

class BadRequest(PmxtError):
    """400 Bad Request - The request was malformed or contains invalid parameters."""
    pass

class AuthenticationError(PmxtError):
    pass

class PermissionDenied(PmxtError):
    pass

class NotFoundError(PmxtError):
    pass

class InvalidOrder(PmxtError):
    """400 Bad Request - The order parameters are invalid."""
    pass

class InsufficientFunds(PmxtError):
    pass

(PmxtError.__init__, line 16: def __init__(self, message: str, code: str = "UNKNOWN_ERROR", ...).)

Confirmed real, directly-raised call sites that hit this gap — e.g. sdks/python/pmxt/client.py:709,711,717,719,724,725,748,750,815,819 (raise InvalidOrder(...) with no code= kwarg) and sdks/python/pmxt/_hosted_mappers.py:28.

Expected

Every Python error subclass should hardcode its code the same way its TypeScript counterpart does, so err.code matches across languages regardless of whether the instance was built via from_server_error (which explicitly passes code=) or raised directly by client-side validation.

Impact

Application code that branches on error.code == "INVALID_ORDER" (or "BAD_REQUEST", "NOT_FOUND", etc.) to distinguish validation failures works correctly in TypeScript but silently falls through to a default-error branch in Python for every client-side-raised instance of these classes — e.g. every InvalidOrder raised by create_order's validation logic reports code="UNKNOWN_ERROR" instead of "INVALID_ORDER".


Found by automated SDK cross-language drift audit

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions