Skip to content

Learn

Exchange APIs

Bybit API error 10002: request time outside recv_window

Figures on this page are as of 2026-09. Fees, limits and margin tiers change — check the venue's own docs.

Bybit V5 returns retCode: 10002 with the message “The request time exceeds the time window range.” It means the X-BAPI-TIMESTAMP you signed fell outside the window Bybit accepts around its own clock. The fix is almost never in your signing code: sync the machine’s clock, sign each request at the moment you send it, and measure how far you are from GET /v5/market/time.

This page is for anyone seeing 10002 from a bot, an SDK or a hand-rolled signer. It gives the exact rule Bybit applies, explains why the rule is lopsided, and shows how to tell a fast clock from a request that simply waited too long before it left.

What this error actually means

Bybit’s integration guide states the acceptance rule as an inequality. Verbatim:

server_time - recv_window <= timestamp < server_time + 1000

timestamp is the millisecond value you sent in X-BAPI-TIMESTAMP. recv_window is the optional X-BAPI-RECV-WINDOW header, in milliseconds, which defaults to 5000. Read the two sides separately:

Your timestamp is…ToleratedControlled by
Behind server time (older)Up to recv_window ms — 5000 by defaultThe X-BAPI-RECV-WINDOW header
Ahead of server time (in the future)Less than 1000 msNothing you send

Being ahead is tolerated far less than being behind, and raising recv_window does not change that. The window only moves the lower bound. A clock running 1.5 seconds fast fails every request, whatever window you send.

Why the rule is shaped this way is our reading, not Bybit’s wording: a genuine request is always a little “behind” by the time it arrives, because it spent time on the network. A timestamp from the future can only come from a clock that runs fast. Bybit’s guide adds that the window also protects against replay, that a smaller window “is more secure”, and recommends keeping local time NTP-synchronised.

The same error table also lists -1, “request expired: o@0, now[] diff[]”, which is also time-related. We did not find further explanation of when Bybit returns it instead of 10002; if you see it, run the same checks below.

Because the timestamp is part of the signed string, this is also why a clock problem looks like an authentication problem — see what HMAC request signing is.

The usual cause: your clock is off, usually fast

Measure before you change anything. The envelope of every V5 response carries a time field, so the server-time endpoint gives you a direct comparison:

import time, requests

t0 = time.time() * 1000
r = requests.get("https://api.bybit.com/v5/market/time", timeout=5)
t1 = time.time() * 1000

server_ms = r.json()["time"]         # common envelope field
offset = (t0 + t1) / 2 - server_ms   # positive = your clock is ahead
print(f"offset {offset:+.0f} ms, round trip {t1 - t0:.0f} ms")

How to read the number, using the default window:

  • Positive and approaching +1000 ms — you are close to the ahead limit. This is the dangerous direction, because the margin is small and no header widens it.
  • Negative and approaching −5000 ms (or your configured window) — you are close to the behind limit. Latency eats into this budget too.
  • Within a few hundred milliseconds of zero — the clock is probably fine; go to the other causes.

The measurement is only as precise as half the round trip, so run it a few times. Use the testnet host (https://api-testnet.bybit.com) if that is where your requests go.

Common reasons a clock drifts: NTP not running on a minimal cloud image, a virtual machine resumed from suspend, a container inheriting a wrong host clock, or a coarse default sync interval. The general fixes are in clock sync and timestamp errors.

Other causes, in order of likelihood

1. The request was signed, then waited. The timestamp is fixed when you sign. If the signed request then sits in a queue, a client-side rate limiter or a retry backoff, it ages. A request signed and held for six seconds fails the default window even with a perfect clock. The classic version is a retry that re-sends the same signed request after a delay instead of signing it again.

2. recv_window set too small. Someone set it to a low value “for security”. That is a legitimate choice, but it leaves latency and small drift very little room on the behind side.

3. Seconds instead of milliseconds. int(time.time()) is seconds. A timestamp that is a thousand times too small lands decades behind server time and fails the lower bound on every request. The reverse mistake (microseconds) lands far in the future.

4. A slow network path. A long route or a congested proxy spends part of the behind budget before the request arrives. This shows up as failures that correlate with latency spikes.

How to confirm which one you have

What you seeMost likely cause
Every request fails; measured offset is positive and near or past +1000 msFast clock
Every request fails; timestamp is ten digits instead of thirteenSeconds, not milliseconds
Fails only on retries, or after a burst is queuedSigned-then-waited
Intermittent; offset changes between runsClock drifting, NTP not holding it
One host fails, another with the same code worksThat host’s clock
You get 10004 insteadThe window check passed — look at the signature, see Bybit API error 10004

Log three numbers on each 10002: the timestamp you sent, the time field from the response envelope, and how long the request waited between signing and sending. Those three settle almost every case.

Fixing it without weakening anything

  • Run NTP and verify it is actually synchronising, not merely installed.
  • Sign at send time. Build, sign and send in one function, and sign again on every retry.
  • Do not raise recv_window as the fix. It cannot help a fast clock at all, and on the behind side it trades away the replay protection the window exists for. Widen it only for a genuinely slow route, deliberately.
  • Log the offset at startup. One request to /v5/market/time, one log line. A surprising number is then visible before the first order.

For automation, 10002 is a refusal: Bybit answered, and the request was not executed. Resending the identical signed request fails again. A freshly signed retry after the clock is fixed is fine; a tight loop is not — it only adds rate-limit pressure. The broader pattern is in error handling patterns for trading APIs.

FAQ

What does Bybit error 10002 mean?

It means the X-BAPI-TIMESTAMP on your signed request fell outside the window Bybit accepts. The documented rule is server_time - recv_window <= timestamp < server_time + 1000, so a request may be up to recv_window milliseconds behind server time but less than one second ahead. The usual cause is a drifting system clock.

Why does increasing recv_window not fix error 10002?

Because recv_window only widens the tolerance for timestamps that are behind server time. The ahead limit is fixed at under 1000 ms by Bybit’s rule. If your clock runs fast by more than a second, every request fails no matter what window you send; the only fix is synchronising the clock.

What is the default recv_window on Bybit?

5000 milliseconds, used when you do not send the optional X-BAPI-RECV-WINDOW header. Bybit’s guide describes a smaller window as more secure, because the window also bounds how long a captured request could be replayed.

How do I check my clock against Bybit’s server time?

Call GET /v5/market/time, note your local time before and after the call, and compare the midpoint with the time field in the response envelope. A positive difference means your clock is ahead. Repeat a few times, since the result is only as precise as half the round trip.