Drift
Router.sql() was added in commit d8ca8fb (feat(sdk): add Router.sql() and cross-venue Router.fetchOrderBook(), #1129/#1670). On a failed request, TypeScript's implementation throws a plain, untyped Error for most failure shapes, while Python's implementation always raises a typed PmxtError subclass, matching the rest of the SDK's error contract.
TypeScript SDK
sdks/typescript/pmxt/router.ts:671-703 (async sql(query: string): Promise<SqlResult>):
if (!response.ok) {
const body = await response.json().catch(() => ({}));
if (body.error && typeof body.error === 'object') {
const { fromServerError } = await import('./errors.js');
throw fromServerError(body.error);
}
throw new Error(body.message || body.error || response.statusText);
}
...
} catch (error) {
if (error instanceof Error) throw error;
throw new Error(`Failed to sql: ${error}`);
}
fromServerError (which returns a PmxtError subclass) is only reached when body.error is present and is an object. Any other failure — a string error field, a message-only body, a non-JSON body (falls back to {} via .catch(() => ({}))), or a non-2xx response with an unparseable payload — throws a bare Error via body.message || body.error || response.statusText, or via the catch-all Failed to sql: ${error}. router.ts does not import PmxtError at all (verified: only Exchange, ExchangeOptions, logger, and model types are imported at the top of the file), so there is no static-analysis signal at this call site that anything other than Error can escape.
This differs from the rest of Exchange's hosted/generated methods, which route failures through PmxtError-returning helpers consistently.
Python SDK
sdks/python/pmxt/router.py:694-730 (def sql(self, query: str) -> SqlResult):
try:
response = self._fetch_with_retry(
lambda: self._api_client.call_api(
method="POST", url=url, body={"query": query}, header_params=headers,
)
)
response.read()
raw = json.loads(response.data)
except ApiException as e:
raise self._parse_api_exception(e) from None
_parse_api_exception (sdks/python/pmxt/client.py:474) always returns a PmxtError subclass, so every failure path for sql() in Python raises a typed, catchable PmxtError.
Expected
Every public SDK method should raise the SDK's own typed error hierarchy (PmxtError and subclasses) on failure in both languages, per the documented contract in /api-reference/errors ("the same except/catch clause works in both hosted and self-hosted modes"). TypeScript's sql() should route all non-ok responses through fromServerError (or wrap the fallback in PmxtError), not a bare Error.
Impact
A caller who writes catch (e) { if (e instanceof PmxtError) ... } around router.sql(...) in TypeScript will miss failures where the hosted /v0/sql endpoint returns an error body without a structured error object (e.g. a plain-text 500, a {"message": "..."} shape, or a non-JSON body) — the same query in Python would raise a catchable PmxtError for the equivalent failure.
Found by automated SDK cross-language drift audit
Drift
Router.sql()was added in commit d8ca8fb (feat(sdk): add Router.sql() and cross-venue Router.fetchOrderBook(), #1129/#1670). On a failed request, TypeScript's implementation throws a plain, untypedErrorfor most failure shapes, while Python's implementation always raises a typedPmxtErrorsubclass, matching the rest of the SDK's error contract.TypeScript SDK
sdks/typescript/pmxt/router.ts:671-703(async sql(query: string): Promise<SqlResult>):fromServerError(which returns aPmxtErrorsubclass) is only reached whenbody.erroris present and is an object. Any other failure — a stringerrorfield, amessage-only body, a non-JSON body (falls back to{}via.catch(() => ({}))), or a non-2xx response with an unparseable payload — throws a bareErrorviabody.message || body.error || response.statusText, or via the catch-allFailed to sql: ${error}.router.tsdoes not importPmxtErrorat all (verified: onlyExchange,ExchangeOptions,logger, and model types are imported at the top of the file), so there is no static-analysis signal at this call site that anything other thanErrorcan escape.This differs from the rest of
Exchange's hosted/generated methods, which route failures throughPmxtError-returning helpers consistently.Python SDK
sdks/python/pmxt/router.py:694-730(def sql(self, query: str) -> SqlResult):_parse_api_exception(sdks/python/pmxt/client.py:474) always returns aPmxtErrorsubclass, so every failure path forsql()in Python raises a typed, catchablePmxtError.Expected
Every public SDK method should raise the SDK's own typed error hierarchy (
PmxtErrorand subclasses) on failure in both languages, per the documented contract in/api-reference/errors("the sameexcept/catchclause works in both hosted and self-hosted modes"). TypeScript'ssql()should route all non-ok responses throughfromServerError(or wrap the fallback inPmxtError), not a bareError.Impact
A caller who writes
catch (e) { if (e instanceof PmxtError) ... }aroundrouter.sql(...)in TypeScript will miss failures where the hosted/v0/sqlendpoint returns an error body without a structurederrorobject (e.g. a plain-text 500, a{"message": "..."}shape, or a non-JSON body) — the same query in Python would raise a catchablePmxtErrorfor the equivalent failure.Found by automated SDK cross-language drift audit