Current code
src/polymarket/models/clob/order_book.py, lines 33–52:
@field_validator("timestamp", mode="before")
@classmethod
def _parse_timestamp(cls, value: object) -> datetime | None:
if value in (None, ""):
return None
if isinstance(value, datetime):
return value
if isinstance(value, str):
try:
ms = int(value) # ← accepts " 1710000000000", "-1", "+1"; no isdecimal() guard
except ValueError as error:
msg = f"invalid epoch-ms timestamp: {value!r}"
raise ValueError(msg) from error
The canonical EpochMsTimestamp type (src/polymarket/models/clob/_validators.py, line 42) rejects whitespace-padded and sign-prefixed strings via value.isdecimal(). Its own docstring (line 41) explicitly calls out the gap:
"Unsigned digits only; int() alone would accept '-1', '+1', ' 1 ', etc."
The test suite (test_streams_market_events.py:253–256) asserts that " 1710000000000" and "1710000000000 " raise ValidationError for EpochMsTimestamp. OrderBook._parse_timestamp silently accepts both.
Reproduction
from polymarket.models.clob.order_book import OrderBook
# Should raise ValidationError — does not
ob = OrderBook(timestamp=" 1710000000000", bids=[], asks=[])
print(ob.timestamp) # prints a valid datetime; no error raised
# EpochMsTimestamp (used by every sibling model) correctly rejects this
from polymarket.models.clob._validators import EpochMsTimestamp
from pydantic import TypeAdapter
ta = TypeAdapter(EpochMsTimestamp)
ta.validate_python(" 1710000000000") # raises ValidationError
Impact
OrderBook is the return type of ClobClient.get_order_book() and the payload type for the book WebSocket event. It is the most-used streaming model. A wire message with a whitespace-padded timestamp (malformed feed, protocol edge case, or future spec change) will parse silently into OrderBook but raise ValidationError on any sibling model that processes the same timestamp field, creating an inconsistent validation surface. Callers that rely on uniform rejection behaviour across all CLOB models will see silent corruption only for OrderBook.
Historical context
order_book.py was created in commit 26865e6 (May 14) before EpochMsTimestamp existed. EpochMsTimestamp was introduced in commit 599b8e3 (May 15) and was applied to all eight timestamp fields in market_events.py (MarketBookPayload, MarketPriceChangePayload, MarketLastTradePricePayload, MarketTickSizeChangePayload, MarketBestBidAskPayload, NewMarketPayload, MarketResolvedPayload), but order_book.py was never updated.
Suggested fix
Replace the bespoke field_validator with the canonical type:
# before
timestamp: datetime | None = None
@field_validator("timestamp", mode="before")
@classmethod
def _parse_timestamp(cls, value: object) -> datetime | None:
... # 20-line bespoke validator
# after
from polymarket.models.clob._validators import EpochMsTimestamp
timestamp: EpochMsTimestamp = None
This removes the duplication, enforces the isdecimal() guard, and aligns OrderBook with every other CLOB model that carries a timestamp field.
Related
Current code
src/polymarket/models/clob/order_book.py, lines 33–52:The canonical
EpochMsTimestamptype (src/polymarket/models/clob/_validators.py, line 42) rejects whitespace-padded and sign-prefixed strings viavalue.isdecimal(). Its own docstring (line 41) explicitly calls out the gap:The test suite (
test_streams_market_events.py:253–256) asserts that" 1710000000000"and"1710000000000 "raiseValidationErrorforEpochMsTimestamp.OrderBook._parse_timestampsilently accepts both.Reproduction
Impact
OrderBookis the return type ofClobClient.get_order_book()and the payload type for thebookWebSocket event. It is the most-used streaming model. A wire message with a whitespace-padded timestamp (malformed feed, protocol edge case, or future spec change) will parse silently intoOrderBookbut raiseValidationErroron any sibling model that processes the same timestamp field, creating an inconsistent validation surface. Callers that rely on uniform rejection behaviour across all CLOB models will see silent corruption only forOrderBook.Historical context
order_book.pywas created in commit 26865e6 (May 14) beforeEpochMsTimestampexisted.EpochMsTimestampwas introduced in commit 599b8e3 (May 15) and was applied to all eight timestamp fields inmarket_events.py(MarketBookPayload,MarketPriceChangePayload,MarketLastTradePricePayload,MarketTickSizeChangePayload,MarketBestBidAskPayload,NewMarketPayload,MarketResolvedPayload), butorder_book.pywas never updated.Suggested fix
Replace the bespoke
field_validatorwith the canonical type:This removes the duplication, enforces the
isdecimal()guard, and alignsOrderBookwith every other CLOB model that carries a timestamp field.Related
EpochMsTimestampintroduced in docs: sdk-direction get_market examples use positional id but API is keyword-only #49 (May 15) — allmarket_events.pymodels were migrated at that time;order_book.pywas missed.