Skip to content

fix: tick size cache stale — force refresh on order create, better er…#282

Open
kingo233 wants to merge 5 commits intoPolymarket:mainfrom
kingo233:fix/tick-size-cache-stale
Open

fix: tick size cache stale — force refresh on order create, better er…#282
kingo233 wants to merge 5 commits intoPolymarket:mainfrom
kingo233:fix/tick-size-cache-stale

Conversation

@kingo233
Copy link
Copy Markdown

@kingo233 kingo233 commented Feb 23, 2026

fix: tick size cache — force refresh on order create, clearer error on reject

Overview

This PR fixes the case where orders are rejected by the CLOB because the client used a stale tick size from its cache after the order book’s tick size changed on the server. It does two things: (1) always fetches the current tick size from the CLOB when creating/signing orders, and (2) raises a dedicated TickSizeRejectedError with a clear message when the API rejects an order due to tick size or price precision, so users know to clear the cache and retry.

Description

Problem: The client caches each market’s minimum tick size (from get_tick_size) for a TTL. If the CLOB updates a market’s tick size, the cache can still hold the old value. Users who rely on get_tick_size (or who signed orders earlier) may then submit orders with an outdated tick size and get rejected by the API, with no indication that the failure is due to cache vs. CLOB.

Changes:

  • Force refresh when creating orders: create_order and create_market_order now call __resolve_tick_size(..., force_refresh=True), so the tick size used for signing is always fetched from the CLOB and never taken from cache. This prevents rejections caused by stale tick size on the create/sign path.

  • get_tick_size(token_id, force_refresh=False): A new optional argument force_refresh skips the cache and fetches from the API, then updates the cache. Docstring updated to explain that when the market’s tick size may have changed, callers should use force_refresh=True or call clear_tick_size_cache(token_id) first.

  • TickSizeRejectedError: When post_order or post_orders receives an API error whose message suggests tick size or price precision (e.g. contains "tick", "precision", "minimum_tick"), the client raises TickSizeRejectedError instead of a generic PolyApiException. The message tells the user to clear the tick size cache and retry. The original API exception is preserved as __cause__.

  • Package export: TickSizeRejectedError is exported from py_clob_client so callers can catch it and implement retry or user-facing messaging.

  • Documentation: README now has a “Tick size and order rejection” section describing cache behavior, when to use force_refresh / clear_tick_size_cache, and how to handle TickSizeRejectedError. Notes section references this for order-rejection issues.

Testing instructions

  • Run the test suite: pytest tests/ -v. If the environment hits the eth_typing / ContractName import error when loading pytest plugins, fix the environment (e.g. pip install 'eth_typing<4.2.0' or pip install -U web3) then re-run.
  • Manually: after a market’s tick size changes on the CLOB, confirm that new orders created via create_order / create_market_order still succeed (tick size is refreshed). When the API rejects an order with a tick-size-related error, confirm that TickSizeRejectedError is raised and the message suggests clearing the cache and retrying.

Types of changes

  • Bug fix/behavior correction
  • Refactor/enhancement
  • New feature
  • Breaking change
  • Other, additional

Notes

  • Default behavior of get_tick_size is unchanged (still uses cache). Only the order-creation path forces a refresh.
  • Other code paths (e.g. RFQ) that use __resolve_tick_size still use the cache unless they are updated to pass force_refresh=True where appropriate.
  • Detection of “tick-size-related” errors is heuristic (message contains "tick", "precision", or "minimum_tick"). If the CLOB uses different wording, those rejections will still be raised as PolyApiException.

Status

  • Prefix PR title with [WIP] if necessary (changes not yet made).
  • Add tests to cover changes as needed.
  • Update documentation/changelog as needed.
  • Verify all tests run correctly in CI and pass.
  • Ready for review/merge.

Note

Medium Risk
Changes order creation and error-handling behavior on the trading path, which could affect how clients retry/handle failed submissions; logic is small and covered by focused tests.

Overview
Prevents stale tick-size cache from causing order rejections by forcing a fresh get_tick_size(..., force_refresh=True) when create_order/create_market_order resolve tick size for signing.

Adds get_tick_size(token_id, force_refresh=False) and introduces TickSizeRejectedError, raised from post_order/post_orders when a PolyApiException message looks tick/precision-related (with helpers to flatten/inspect structured error payloads); exports the exception from py_clob_client, documents cache/refresh guidance in README.md, and adds unit tests for the error detection/flattening logic.

Written by Cursor Bugbot for commit b077da8. This will update automatically on new commits. Configure here.

@kingo233 kingo233 requested a review from a team as a code owner February 23, 2026 08:08
Comment thread py_clob_client/exceptions.py
So that except PolyApiException continues to catch all API errors including
tick-size rejections; preserves status_code from wrapped api_exception.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread py_clob_client/client.py Outdated
Comment thread py_clob_client/client.py
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

Comment thread py_clob_client/client.py
Comment thread py_clob_client/client.py
- Add _flatten_error_message() to recursively extract string from
  dict/list API error payloads (e.g. {"error": {"message": "..."}})
- Use flattened text in _is_tick_size_related_error() so keyword search
  works for nested structures; use flattened message for TickSizeRejectedError
- Add tests for string, dict, nested dict, and list error payloads

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant