Polymarket’s SDK lineage moved again. The legacy @polymarket/clob-client repo was archived on May 25, 2026 — its README now points developers to the new TypeScript SDK — and Polymarket is consolidating onto two unified beta SDKs:

  • py-sdk — published to PyPI as polymarket-client (beta: pip install --pre polymarket-client)
  • ts-sdk — published to npm as @polymarket/client (beta 0.1.0-beta.2: npm install @polymarket/client@beta)

Both are explicitly beta, and in the week of May 26–28, 2026 eight bugs were filed across the two repos. They cluster around the same problems the transitional py-clob-client-v2 line hit after the CLOB V2 cutover — above all, POLY_1271 deposit-wallet authentication. This brief documents each open issue with the exact symptom and a workaround. It complements our py-clob-client-v2 bug tracker, which covers the previous SDK generation.

Every issue below was open as of June 1, 2026, with no maintainer fix merged. Both SDKs are pre-1.0 — pin a version and expect churn.

POLY_1271 deposit-wallet auth is broken in both new SDKs

This is the dominant cluster, and it is the same defect we tracked against py-clob-client-v2, now carried into the unified SDKs.

New-style accounts (Magic/email and MetaMask deposit wallets) must trade through a deposit wallet with signature_type=3 (POLY_1271, a contract-wallet signature verified via EIP-1271). The problem is in L1 authentication — the step that creates or derives your API key. Both SDKs sign the ClobAuth message with the bare EOA signer.address, ignoring the deposit-wallet shape:

  • py-sdk #55sign_api_key_auth uses signer.address for ClobAuth, ignoring the POLY_1271 deposit-wallet shape.
  • ts-sdk #73beginAuthentication signs ClobAuth with the EOA address, the same way.

Because the API key is bound to the EOA, the later order — signed as the deposit wallet — no longer matches the key. The CLOB rejects it:

HTTP 400: {"error":"the order signer address has to be the address of the API KEY"}

The root cause was first documented in clob-client-v2 #65createApiKey() / create_or_derive_api_key() don’t EIP-1271-wrap the L1 auth headers for POLY_1271 wallets — and reproduced in py-clob-client-v2 #64 and #71. The Rust SDK is the only client that wraps the authentication step correctly today.

Workaround: Derive your API credentials from the deposit-wallet context (not the bare EOA), and confirm the deposit wallet is deployed, funded, and approved. If you need POLY_1271 today, trade through the Rust SDK until a fix lands, or — if your account allows it — use an EOA / Proxy / Gnosis Safe signature type that doesn’t depend on the broken EIP-1271 wrapping. See the POLY_1271 smart-contract wallet guide and auth troubleshooting for the full credential-derivation flow.

Builder-fee lookups crash market-order construction

Both SDKs fetch builder-fee rates while assembling a market order, but neither handles a 404 for an unregistered builder code — so the exception propagates and takes down order construction instead of degrading gracefully.

  • py-sdk #56fetch_builder_fee_rates lacks 404 handling; market-order construction crashes on an unregistered builder code.
  • ts-sdk #74fetchBuilderFeeRates lacks 404 handling; prepareMarketOrder with an unregistered builderCode crashes instead of degrading.

The fee endpoint returns a plain 404 ({"error":"builder code not found"}) for any code you haven’t registered, and the SDK turns that into an unhandled error.

Workaround: Don’t pass a builder code you haven’t registered. Where you do use one, guard the lookup, catch the 404, and build the order without a builder fee:

# py-sdk #56: fetch_builder_fee_rates raises on a 404 for an unregistered code,
# which crashes market-order construction. Degrade instead of dying.
def safe_builder_fee(client, builder_code):
    try:
        return client.fetch_builder_fee_rates(builder_code)
    except Exception as e:  # narrow to the SDK's request-error type once exposed
        msg = str(e).lower()
        if "not found" in msg or "404" in msg:
            return None  # build the order without a builder fee
        raise

Gasless wallet creation has no retry loop

  • py-sdk #61submit_deposit_wallet_create / _sync import GASLESS_SUBMIT_RETRY_ATTEMPTS but never loop on it, so a single transient relayer error aborts wallet creation on the first failure.

Workaround: Wrap the call in your own exponential-backoff retry. Wallet creation is idempotent here — there’s no nonce to burn — so retrying is safe:

# py-sdk #61: the built-in retry constant is imported but unused. Retry yourself.
import time

def create_deposit_wallet_with_retry(client, attempts=5):
    for i in range(attempts):
        try:
            return client.submit_deposit_wallet_create()
        except Exception:
            if i == attempts - 1:
                raise
            time.sleep(2 ** i)  # exponential backoff

See the Polymarket rate-limits guide for backoff patterns that also respect 429s.

Trade timestamps are parsed in the wrong unit (silent data corruption)

  • ts-sdk #76ClobTradeSchema.match_time and last_update are typed as epoch-milliseconds, but the /data/trades REST API returns epoch-seconds strings.

This one is dangerous precisely because it’s silent: nothing throws. Parsing a seconds value as milliseconds just produces a date in 1970. For example, the raw value 1710000000 (March 2024) parsed as milliseconds resolves to 1970-01-20T.... Any agent that keys off trade time — P&L windows, “trades since,” dedup by timestamp — will be quietly wrong.

Workaround: Normalize seconds-vs-milliseconds before you trust a trade timestamp:

// ts-sdk #76: /data/trades sends epoch-SECONDS, but the schema expects ms.
// Normalize before constructing a Date.
function toMillis(ts: string | number): number {
  const n = Number(ts);
  return n < 1e12 ? n * 1000 : n; // seconds -> ms; leave real ms alone
}
// new Date(toMillis("1710000000")) -> 2024-03-09T...  (not 1970)

OrderBook timestamps skip the strict validator

  • py-sdk #63OrderBook.timestamp is parsed with int() instead of the strict EpochMsTimestamp type, bypassing the whitespace-rejection guard the other models use.

Lower severity than the others, but it means a malformed or padded timestamp the rest of the SDK would reject slips through on the order book. Compare the REST /book payload against the WebSocket book event and you can see the inconsistency.

Workaround: If you depend on book timestamps, validate them strictly yourself:

# py-sdk #63: OrderBook.timestamp uses int(), skipping the strict guard.
def epoch_ms(value: str) -> int:
    if not value.isdigit():  # rejects " 123", "123 ", "1.2e3", etc.
        raise ValueError(f"non-epoch-ms timestamp: {value!r}")
    return int(value)

See the Polymarket WebSocket guide for reconciling REST and stream payloads.

createSecureClient rejects nonce: 0

  • ts-sdk #67createSecureClient rejects nonce: 0 even though 0 is documented as the default. The nonce schema is validated as positive-only, so the documented default value is itself rejected.

Workaround: Omit the nonce field when you mean zero — the default applies:

import { createSecureClient } from "@polymarket/client";

// ts-sdk #67: nonce is validated positive-only, so nonce: 0 throws.
const client = await createSecureClient({ signer }); // nonce defaults to 0
// NOT: createSecureClient({ signer, nonce: 0 }) -> validation error

This is a developer-experience paper cut, not a fund-safety problem.

Defensive patterns for beta SDKs

Until these land fixes, treat both SDKs as pre-1.0 and code defensively:

  • Verify deposit-wallet auth before you trade. Place one tiny order on a test market and confirm it isn’t rejected with the order signer address has to be the address of the API KEY before running any real strategy.
  • Wrap the fragile paths. Guard builder-fee lookups (catch the 404), wallet creation (retry with backoff), and any timestamp you read from /data/trades (normalize seconds → ms).
  • Don’t trust silent values. The timestamp bug throws nothing — add an assertion that parsed trade dates fall in a sane range.
  • Pin versions. polymarket-client needs --pre, and the npm latest tag is a canary build, not the beta — install @polymarket/client@beta explicitly.
  • Keep the Rust SDK in your back pocket for POLY_1271 deposit-wallet flows, which it handles correctly today.

Summary table

IssueSDKSymptomWorkaround
#55 / #73py & tsPOLY_1271 deposit-wallet orders rejected: signer address has to be the address of the API KEYDerive creds from the deposit-wallet context; use the Rust SDK until fixed
#56 / #74py & tsBuilder-fee 404 crashes market-order constructionCatch the 404 and degrade; don’t pass unregistered builder codes
#61pyGasless wallet creation has no retry loopWrap create in your own backoff retry (idempotent)
#76tsTrade timestamps parsed as ms but API sends seconds (1970 dates)Normalize seconds → ms before use
#63pyOrderBook.timestamp skips the strict epoch-ms guardValidate book timestamps yourself (digits-only)
#67tscreateSecureClient rejects nonce: 0Omit nonce to get the zero default

Further reading