◈   ⌘ api · Intermediate

Binance API Error Code List: Complete Trader's Guide

Master Binance API error codes with real code examples. Learn what each error means, how to handle them in Python, and keep your trading bots running smoothly.

Uncle Solieditor · voc · 06.05.2026 ·views 24
◈   Contents
  1. → Understanding Binance API Error Structure
  2. → System and Network Error Codes (-1000 to -1099)
  3. → Request and Parameter Error Codes (-1100 to -1199)
  4. → Order and Trading Error Codes (-2010 to -2015)
  5. → Rate Limits: The Most Expensive Errors to Ignore
  6. → Frequently Asked Questions
  7. → Building Resilient API Integrations

If you've built a trading bot or written any automation against Binance, you've hit error codes. That -1121 that killed your order at 3am. The -2010 that fires right when volatility spikes and your bot tries to place 40 orders in two seconds. These aren't random noise — every code is specific, and once you understand what each one means, debugging goes from guesswork to a five-minute fix.

This guide covers the full Binance REST API error code list, what triggers each one, and how to handle them correctly in production Python code. The same principles apply whether you're on Binance Spot, Futures, or Margin — and many of these patterns translate directly to Bybit, OKX, and other exchange APIs that follow similar conventions.

Understanding Binance API Error Structure

Every error response from the Binance API follows the same JSON shape: a numeric code and a human-readable message. The code is what matters for programmatic handling — the message is helpful for logging but you should never parse it for logic.

import requests
import hmac
import hashlib
import time
from urllib.parse import urlencode

API_KEY = 'your_api_key'
API_SECRET = 'your_api_secret'
BASE_URL = 'https://api.binance.com'

def get_signed_params(params: dict) -> dict:
    params['timestamp'] = int(time.time() * 1000)
    query_string = urlencode(params)
    signature = hmac.new(
        API_SECRET.encode('utf-8'),
        query_string.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()
    params['signature'] = signature
    return params

def place_order(symbol: str, side: str, quantity: float):
    endpoint = '/api/v3/order'
    params = get_signed_params({
        'symbol': symbol,
        'side': side,
        'type': 'MARKET',
        'quantity': quantity
    })
    headers = {'X-MBX-APIKEY': API_KEY}
    response = requests.post(BASE_URL + endpoint, params=params, headers=headers)
    data = response.json()
    
    if 'code' in data:
        print(f'Error {data["code"]}: {data["msg"]}')
        return None
    return data

The critical thing to notice: Binance returns HTTP 200 even for some errors. Always check for the 'code' key in the response body, not just the HTTP status code. Relying only on status codes will cause silent failures in your bot.

System and Network Error Codes (-1000 to -1099)

These codes indicate problems on Binance's infrastructure side, or malformed requests before they reach order processing logic. Most -1xxx errors are your code's fault, not Binance's.

Core System Error Codes
CodeMeaningCommon Cause
−1000UNKNOWNUnexpected server error — retry with backoff
−1001DISCONNECTEDConnection dropped mid-request
−1002UNAUTHORIZEDAPI key missing or invalid format
−1003TOO_MANY_REQUESTSRate limit hit — back off immediately
−1006UNEXPECTED_RESPNon-standard response — log and retry
−1007TIMEOUTRequest took too long — check network
−1013INVALID_MESSAGEBad JSON in request body
−1015TOO_MANY_ORDERSOrder rate limit exceeded
−1020UNSUPPORTED_OPERATIONMethod not allowed for this endpoint
−1021INVALID_TIMESTAMPServer/client time drift > 1000ms
−1022INVALID_SIGNATUREHMAC signature mismatch
Time sync is the most common silent killer. The -1021 INVALID_TIMESTAMP error fires when your system clock drifts more than 1000ms from Binance's server time. Run NTP sync on any server running a bot, and call GET /api/v3/time periodically to verify your offset stays within bounds.

Request and Parameter Error Codes (-1100 to -1199)

These are validation errors — your request reached Binance but failed parameter checks before any order logic ran. They're the easiest to fix once you know what each one means.

Parameter Validation Error Codes
CodeMeaningFix
−1100ILLEGAL_CHARSSpecial chars in a field — sanitize inputs
−1101TOO_MANY_PARAMETERSDuplicate or excess params in request
−1102MANDATORY_PARAM_EMPTYRequired field is null or missing
−1103UNKNOWN_PARAMExtra field Binance doesn't recognize
−1104UNREAD_PARAMETERSSome params weren't consumed — check spelling
−1105PARAM_EMPTYA parameter exists but has empty string value
−1106PARAM_NOT_REQUIREDYou sent a param that's only valid for other order types
−1111BAD_PRECISIONToo many decimal places for this symbol
−1112NO_DEPTHOrder book is empty — unusual, log and skip
−1114TIF_NOT_REQUIREDTimeInForce sent with order type that ignores it
−1115INVALID_TIFBad TimeInForce value — use GTC, IOC, or FOK
−1116INVALID_ORDER_TYPEOrder type string incorrect or not supported
−1117INVALID_SIDESide must be BUY or SELL exactly

A practical pattern when hitting -1111 (bad precision): Binance's exchange info endpoint tells you the exact step size for each symbol. Fetch it once at startup and use it to round quantities before placing orders. This eliminates an entire class of errors.

import math

def get_step_size(symbol: str) -> float:
    """Fetch the minimum quantity step size for a symbol."""
    response = requests.get(f'{BASE_URL}/api/v3/exchangeInfo?symbol={symbol}')
    info = response.json()
    for filt in info['symbols'][0]['filters']:
        if filt['filterType'] == 'LOT_SIZE':
            return float(filt['stepSize'])
    return 0.001  # fallback

def round_step(quantity: float, step_size: float) -> float:
    """Round quantity down to the nearest valid step."""
    precision = int(round(-math.log10(step_size)))
    return round(math.floor(quantity / step_size) * step_size, precision)

# Usage
step = get_step_size('BTCUSDT')
qty = round_step(0.00314159, step)
print(f'Rounded quantity: {qty}')  # e.g. 0.003

Order and Trading Error Codes (-2010 to -2015)

This range is where most trading bot failures live. These errors fire during order placement and modification — after parameter validation passes but before the order hits the matching engine successfully.

Order Execution Error Codes
CodeMeaningWhat's Actually Happening
−2010NEW_ORDER_REJECTEDCatch-all for order rejection — check msg field
−2011CANCEL_REJECTEDOrder doesn't exist or already filled/canceled
−2013NO_SUCH_ORDEROrder ID not found — may have been filled
−2014BAD_API_KEY_FMTAPI key format wrong — check for whitespace
−2015REJECTED_MBX_KEYIP not whitelisted, or key disabled/expired
−2018BALANCE_NOT_SUFFICIENTNot enough funds — check available balance
−2019MARGIN_NOT_SUFFICIENTMargin account underfunded
−2021PRICE_QTY_EXCEED_HARD_LIMITSOrder exceeds max notional or qty limits

The -2010 code is intentionally vague — Binance uses it as a bucket for many rejection reasons. The actual reason lives in the 'msg' field. Common messages inside -2010: 'Account has insufficient balance', 'Filter failure: PRICE_FILTER', 'Filter failure: MIN_NOTIONAL'. Build a handler that logs the full message for this specific code.

import time
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('binance_bot')

RETRYABLE_CODES = {-1000, -1001, -1006, -1007}
RATE_LIMIT_CODES = {-1003, -1015}

def safe_place_order(symbol: str, side: str, quantity: float, max_retries: int = 3):
    endpoint = '/api/v3/order'
    
    for attempt in range(max_retries):
        params = get_signed_params({
            'symbol': symbol,
            'side': side,
            'type': 'MARKET',
            'quantity': quantity
        })
        headers = {'X-MBX-APIKEY': API_KEY}
        
        try:
            response = requests.post(BASE_URL + endpoint, params=params, headers=headers, timeout=5)
            data = response.json()
        except requests.exceptions.Timeout:
            logger.warning(f'Attempt {attempt+1}: Request timed out, retrying...')
            time.sleep(2 ** attempt)
            continue
        
        if 'code' not in data:
            logger.info(f'Order placed: {data["orderId"]}')
            return data
        
        code = data['code']
        msg = data.get('msg', '')
        
        if code in RATE_LIMIT_CODES:
            wait = 60 if code == -1003 else 10
            logger.warning(f'Rate limit hit (code {code}), waiting {wait}s')
            time.sleep(wait)
            continue
        elif code in RETRYABLE_CODES:
            logger.warning(f'Retryable error {code}: {msg}, attempt {attempt+1}')
            time.sleep(2 ** attempt)
            continue
        elif code == -2010:
            logger.error(f'Order rejected — full message: {msg}')
            return None  # Don't retry rejections
        elif code == -1021:
            logger.error('Timestamp error — check system clock sync')
            return None
        else:
            logger.error(f'Unhandled error {code}: {msg}')
            return None
    
    logger.error(f'Max retries reached for {symbol} {side}')
    return None

Rate Limits: The Most Expensive Errors to Ignore

Binance enforces multiple rate limit tiers simultaneously. Ignoring them doesn't just cost you errors — it gets your IP or API key banned. The limits are tracked in response headers on every successful request.

Bybit and OKX use similar rate limit structures, and tools like VoiceOfChain that aggregate real-time signals across multiple exchanges are specifically designed to handle the edge case where you need to act fast on a signal without burning your rate limit budget on price polling. Instead of hammering the API for price updates, you consume a WebSocket or signal stream and reserve your weight budget for actual order operations.

Frequently Asked Questions

What does Binance error -1121 mean?
Error -1121 means INVALID_SYMBOL — the trading pair you specified doesn't exist or is formatted incorrectly. Always use uppercase (BTCUSDT not btcusdt) and verify the pair is active on the specific market (Spot vs Futures) you're querying. Fetch the exchange info endpoint to validate symbols at startup.
Why does my Binance API keep returning -1003 even after I slow down requests?
The -1003 rate limit can persist after the ban window expires if you continue hitting the endpoint. After receiving -1003, wait the full ban window (check the Retry-After header if present, otherwise wait 60 seconds minimum), then gradually ramp back up. Using multiple IP addresses to bypass rate limits violates Binance ToS.
How do I fix -1022 INVALID_SIGNATURE on Binance API?
Invalid signature usually comes from one of three causes: trailing whitespace in your API secret, incorrect parameter ordering before hashing, or using string concatenation instead of proper URL encoding. Use urlencode() on the full parameter dictionary before computing the HMAC-SHA256. Regenerating the API key pair also resolves issues caused by key corruption.
Is error -2010 always my fault or can it be a Binance issue?
-2010 is almost always a client-side issue — it's Binance's catch-all rejection code. Read the 'msg' field carefully: it will tell you whether it's a balance issue, a filter violation (price too far from market, quantity below minimum), or a position limit. Only in very rare cases during extreme market volatility does it reflect a matching engine issue.
Can I use the same error handling code for Bybit and OKX APIs?
Not directly — each exchange uses its own error code numbering. Bybit uses codes like 10001 for parameter errors, OKX uses 0 for success with errors in a nested 'sCode' field. However, the pattern is the same: check for an error key in every response, map codes to categories (retryable, fatal, rate-limited), and log the full message for catch-all codes. Abstract your exchange client behind a common interface and translate per-exchange errors into a unified error type.
What's the safest way to handle Binance API errors in a live trading bot?
Separate errors into three buckets: fatal (don't retry — -1022, -2015, -2010 with balance rejection), retryable with backoff (-1000, -1001, -1007), and rate-limit pauses (-1003, -1015). Log every error with timestamp, symbol, side, quantity, and the full response. Never silently swallow errors — a missed log during a failed order has real money consequences.

Building Resilient API Integrations

The traders who get burned by API errors aren't the ones who hit them — everyone hits them. The ones who get burned are those without systematic error handling. A production bot needs to distinguish between errors that warrant a retry, errors that indicate a logic bug in your code, and errors that require human attention.

Platforms like VoiceOfChain handle this at the infrastructure level for signal delivery — the signal reaches you reliably regardless of what's happening at the exchange API layer. Your job as the bot developer is to handle the execution side: validate your order parameters against live exchange info, respect rate limits proactively rather than reactively, and build an alerting layer that pages you when error rates spike unexpectedly.

The Binance error code system is well-documented and consistent — once you've mapped your error handler to cover the codes in this guide, you've covered the vast majority of what you'll encounter in production. The same disciplined approach works whether you're trading on Binance Spot, Binance Futures, or expanding to Bybit, OKX, or KuCoin — the specifics differ, but the architecture is identical.

◈   more on this topic
◉ basics Mastering the ccxt library documentation for crypto traders ⌂ exchanges Mastering the Binance CCXT Library for Crypto Traders ⌬ bots Best Crypto Trading Bots 2025: Profitable AI-Powered Strategies