Skip to content

Learn

Exchange APIs

Bybit API error 10003 — invalid key or too many sessions

CoTrading editorial team Updated: 2026-09-23

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

Bybit’s 10003 means two different things depending on which channel returned it. Over REST it is “API key is invalid. Check whether the key and domain are matched, there are 4 env: mainnet, testnet, mainnet-demo, testnet-demo”. On the WebSocket order-entry channel it is “Too many sessions under the same UID”.

The first is a credential problem you fix by pointing the right key at the right host; the second is a concurrency problem you fix by closing connections. Neither is an expired key — Bybit gives expired keys their own codes. So the first step is not debugging. It is noting where the error came from.

Correction, 2026-09-23: an earlier version of this page said the fork was account type — “too many sessions” on classic accounts, “your api key has expired” under a Unified Trading Account on spot — and pointed to 110028 / 100028 to tell them apart. That was wrong. Bybit’s error page, re-checked today, splits 10003 by channel (REST versus WebSocket order entry); expired keys are -2015 (spot) and 33004 (derivatives); and the unified-account code is 10028, not 110028, which is a position-mode error. Bybit’s docs also mark the classic account as no longer available.

What this error actually means

Bybit’s V5 error page lists 10003 twice, in two different tables:

Where it came backMeaning (verbatim)
REST (UTA table)“API key is invalid. Check whether the key and domain are matched, there are 4 env: mainnet, testnet, mainnet-demo, testnet-demo”
WebSocket order entry“Too many sessions under the same UID”

The REST meaning is about which environment a key belongs to. A key created in one environment does not exist in the others, and each has its own host:

EnvironmentREST host
Mainnethttps://api.bybit.com (alternate https://api.bytick.com), or a regional host
Testnethttps://api-testnet.bybit.com
Demo tradinghttps://api-demo.bybit.com — the key is created on production while in Demo Trading mode

The error text names a fourth environment, testnet-demo; we did not capture a separate host for it in the pages we checked.

Because the environments are separate hosts with separate credentials, a mix-up fails with an authentication error instead of placing an order in the wrong place. That is the safe arrangement — and a REST 10003 is what it looks like when it is working.

The WebSocket meaning is unrelated: a ceiling on concurrent order-entry sessions under one UID.

The usual cause

A key sent to the wrong environment’s host. Bybit’s own FAQ calls a key/domain mismatch the “most likely cause” of 10003. The common shapes:

  • A testnet key with the base URL still set to mainnet, or the reverse — usually because the URL and the credentials are configured in different places and only one of them was changed.
  • A Demo Trading key sent to testnet. Demo Trading is not testnet: its key is created from your production account and works on api-demo.bybit.com. Bybit advises against using Demo Trading on Testnet.
  • A mainnet key sent to api-demo.bybit.com, often after copying a config file from a demo setup.

Fix: derive the host and the credentials from one environment setting so they cannot disagree, and log the host at startup:

BASE, KEY, SECRET = {
    "mainnet": ("https://api.bybit.com", LIVE_KEY, LIVE_SECRET),
    "testnet": ("https://api-testnet.bybit.com", TESTNET_KEY, TESTNET_SECRET),
    "demo": ("https://api-demo.bybit.com", DEMO_KEY, DEMO_SECRET),
}[ENV]
log.info("bybit environment=%s base=%s", ENV, BASE)

One switch, three environments, one log line.

Other causes, in order of likelihood

Bybit’s docs name only the environment mismatch. The ordering below is our editorial judgement.

1. The key string is not the key. A trailing newline or space from copy-paste, a value truncated by an environment file, or the secret pasted where the key belongs. The message says “invalid”, and a corrupted string qualifies.

2. The key was deleted or replaced. A key removed in the UI — for example during a leak response — and still deployed somewhere you forgot about.

3. A regional account on the global host. Bybit runs several regional mainnet hosts (listed in Bybit API key setup). We did not find Bybit documenting which code a regional key returns on api.bybit.com, but if your account was opened through a regional site, check you are calling its host before anything else.

4. On the WebSocket order-entry channel: too many sessions. If the 10003 came back on an order-entry socket, it is the session ceiling, not the key. The causes are usually structural rather than intentional (again editorial):

  • Connections that are not being closed. A reconnect loop that opens a new session without closing the old leaks sessions until you hit the ceiling. The signature is that it appears after hours of running, goes away on restart, and comes back.
  • Several processes on the same UID — a bot, a dashboard and a notebook, each holding its own session.
  • Development alongside production on the same account.
  • Crash-looping containers opening sessions faster than old ones are reaped.

The fix, in order of durability: close sessions on every exit path, including exceptions; reuse one long-lived client per process; back off on reconnect rather than retrying in a tight loop; and give each consumer its own key so you can see which one is holding the sessions. See WebSocket reconnection patterns.

How to confirm which one you have

  1. Which channel returned it? A REST response means key/environment; an order-entry socket means sessions. That one question settles the fork.
  2. For REST, log the host and the first few characters of the key at startup — never the secret. Compare against where the key was created: the testnet site, production, or production in Demo Trading mode.
  3. Make one read-only call, such as Get Account Info, against the host you believe is right. If it succeeds there, the failing path is using a different host or a different key.
  4. Rule out the neighbours, which have their own codes:
CodeMeaning (verbatim)Not 10003 because
-2015“(Spot) Your api key has expired”Expiry has its own code
33004“(Derivatives) Your api key has expired”Same, for derivatives
10004“Error sign, please check your signature generation algorithm.”Key recognised, signature wrong
10005“Permission denied, please check your API key permissions.”Scope, not identity
10010“Unmatched IP, please check your API key’s bound IP addresses.”IP binding
10006“Too many visits. Exceeded the API Rate Limit.”Request rate, not session count
20003 (WS order entry)“Too frequent requests under the same session”Message rate within one session
HTTP 401Wrong key used, or auth params not placed in the request headerHTTP status, not a retCode

The one most often confused with the WebSocket 10003 is 10006. Both sound like “you are doing too much”, but 10003 counts sessions and 10006 counts requests per endpoint. Opening fewer connections fixes one; slowing down fixes the other.

FAQ

Does Bybit error 10003 mean my API key expired?

No. Expired keys have their own codes: -2015, “(Spot) Your api key has expired”, and 33004, “(Derivatives) Your api key has expired”. Over REST, 10003 means the key is invalid for the host you sent it to — most often a mainnet, testnet or demo key used against another environment’s host. An earlier version of this page said otherwise; see the correction above.

Is 10003 different on classic and Unified Trading Accounts?

Not according to the current docs. Bybit’s error page splits 10003 by channel — REST versus WebSocket order entry — not by account type, and Bybit marks the classic account as no longer available. The account-type codes are 10028 (“The API can only be accessed by unified account users.”) and 100028 (“The API cannot be accessed by unified account users.”).

What is the difference between 10003 and 10006?

10006 is a per-UID, per-endpoint request-rate limit. Over REST, 10003 is a credential problem; on WebSocket order entry it is a session count. Neither meaning is about request rate, so the fixes do not overlap.

Why did this start happening after my service had been running fine?

If it is a REST 10003, something changed the key or the host — a deploy that swapped a config, a key deleted in the UI, an environment variable that now points elsewhere. If it is on the order-entry socket, the usual story is a session leak accumulating over hours or days: restarting clears it, and it returns.