Saltar al contenido principal

Referencia de Códigos de Error

Catálogo completo de códigos de error de la API C2C de Binance con 8 categorías de clasificación, patrones de recuperación y soluciones probadas en producción con más de 500K llamadas a la API.

Prioridad de Clasificación

AD_OFFLINERETRY_WITH_SYNC-9000 MESSAGE CHECKRETRIABLE_WITH_BACKOFFRETRY_WITH_VOLUME_SYNCNON_RETRIABLE_BUSINESSSPECIAL_HANDLERPRICE_RANGE_LIMITUNKNOWN

Decodificador del Error -9000

El error -9000 es un código envoltorio. El error real está embebido en el string del mensaje:

  • El mensaje contiene "187049" / "187040" / "187031"RETRY_WITH_VOLUME_SYNC
  • El mensaje contiene "rango limitado" / "limited range"PRICE_RANGE_LIMIT
  • En cualquier otro caso → RETRIABLE_WITH_BACKOFF

Errores a Nivel de Transporte

Estos son códigos de estado HTTP manejados en la capa de transporte, antes de que classify_binance_error() se ejecute.

CódigoNombreAcción
418I'm a teapot (IP Ban)Transport-level HTTP status. Handled before app-level error classification. Indicates temporary IP ban — requires significant cooldown (hours).
429Rate Limit ExceededCan appear as both HTTP status code and Binance app code. Check Retry-After header. Triggers circuit breaker recording.

Categorías de Error

Time Sync Errors

high
-1021-1022

Re-synchronize server time via GET /api/v3/time, wait 0.3s, then retry the request with a fresh timestamp.

Note: -1000 was previously classified here but is actually RETRIABLE_WITH_BACKOFF. Some methods enable per-method sync via BINANCE_RETRY_SYNC_ON_1000.

Ver código de recuperación
async def handle_time_sync_error(client, original_request):
    """Recovery: sync time + retry with fresh timestamp."""
    await client.sync_time()  # GET /api/v3/time
    await asyncio.sleep(0.3)
    # Rebuild request with fresh timestamp — do NOT reuse stale one
    return await original_request()

Retriable (Backoff)

high
-1000429-9000

Exponential backoff with jitter. For 429: read Retry-After header. Circuit breaker opens after threshold failures.

-1000 has a per-method override: when BINANCE_RETRY_SYNC_ON_1000=true, the method also syncs time before retrying. Error -9000 is a wrapper — check the message string for wrapped 187xxx codes before classifying as backoff.

Ver código de recuperación
def calculate_backoff(attempt: int, base_ms=250, cap_ms=30000) -> float:
    """Exponential backoff with full jitter."""
    max_backoff = min(cap_ms, base_ms * (2 ** attempt))
    return random.uniform(0, max_backoff) / 1000.0

# attempt=1: 0-250ms, attempt=2: 0-500ms, ..., capped at 30s
# For 429: also check resp.headers.get("Retry-After")

Volume Sync Errors

critical
187031187049187040

Sleep (configurable via ERROR_187XXX_RETRY_SLEEP_SEC, default 0.3s), re-fetch ad state, retry. Prevention: use price-only payload.

Error 187031 can also arrive wrapped inside -9000. The classifier checks the -9000 message string for '187031', '187049', or '187040' and reclassifies accordingly.

Ver código de recuperación
async def handle_volume_sync(client, adv_no: str, price: str):
    """
    CRITICAL: Use price-only updates to PREVENT this error entirely.

    CORRECT: {"advNo": adv_no, "price": price}
    WRONG:   {"advNo": adv_no, "price": price, "surplusAmount": amount}
    """
    sleep_sec = float(os.getenv("ERROR_187XXX_RETRY_SLEEP_SEC", "0.3"))
    await asyncio.sleep(sleep_sec)
    # Re-fetch current ad state
    ad = await client.get_ad_detail(adv_no)
    # Retry with price-only payload
    return await client.update_ad(adv_no, price=price)

Business Errors (Non-Retriable)

medium
-2019-2015-3026-1013-1111

300-second cooldown block. Log the error. Do not retry — these require manual intervention.

Ver código de recuperación
NON_RETRIABLE_PAUSE_SEC = 300  # 5 minutes

if classify_error(error) == "NON_RETRIABLE_BUSINESS":
    _non_retriable_block_until = time.time() + NON_RETRIABLE_PAUSE_SEC
    _non_retriable_last_code = error.code
    log_event("business_error", code=error.code, message=error.message)
    # Do NOT retry — requires manual fix (insufficient funds, invalid key, etc.)

Price Overlap

high
187055

Find a valid price outside the exclusion zone (current price ± 4 ticks). Max 5 attempts in 60 seconds, then 30-second cooldown.

Ver código de recuperación
async def handle_overlap(target_price, my_prices, tick):
    """
    Binance rejects prices within ±4 ticks of your own ads.
    Example: ad at 41.37, tick=0.01 → zone [41.33, 41.41]
    """
    # Pre-avoid: check before first attempt
    if is_in_exclusion_zone(target_price, my_prices, tick):
        target_price = find_valid_price_outside_exclusion(
            target_price, my_prices, tick
        )

    # Rate limit: max 5 overlap retries in 60s
    if overlap_count > 5:
        await asyncio.sleep(30)
        return

Ad/Merchant Offline

medium
8322983230

Mark ad as paused, record reason and timestamp. Check every 15 seconds if ad came back online. Manual recovery via your application's admin interface.

Ver código de recuperación
if error.code in (83229, 83230):
    ad_paused = True
    ad_paused_reason = (
        "Business closed" if error.code == 83229
        else "Taking a break"
    )
    # Check every 15s if merchant came back online
    # Manual recovery: clear the pause state via your admin interface

Dynamic Price Range

high

Parse the allowed range from the error message, clamp target price to the effective range (intersection of user limits and Binance range), retry.

Detected by message content, not by error code. Binance may wrap this in -9000 or other codes. Keywords: 'rango limitado', 'limited range', 'price range'.

Ver código de recuperación
async def handle_price_range(error_message, target, user_min, user_max):
    """
    Binance imposes ~±10% of reference price. Detection:
    1. Parse from message: "rango limitado de: 34.77-42.49"
    2. Fallback: estimate from USD rate × ±9.5%
    """
    parsed = parse_binance_price_range(error_message)
    if parsed:
        low, high = parsed
    else:
        usd_rate = await get_usd_rate(fiat)
        low, high = usd_rate * 0.905, usd_rate * 1.095

    # Effective range = intersection of user and Binance ranges
    effective_low = max(user_min, low)
    effective_high = min(user_max, high)
    chosen = max(effective_low, min(target, effective_high))

    # Cache for pre-validation (TTL: ENGINE_BINANCE_RANGE_TTL_SEC)
    return chosen

Unknown Errors

low

Conservative exponential backoff. Log with full context for investigation.

Ver código de recuperación
if classify_error(error) == "UNKNOWN":
    log_event("unknown_binance_error",
        code=error.code,
        message=error.message,
        endpoint=endpoint,
    )
    backoff = calculate_backoff(attempt)
    await asyncio.sleep(backoff)

Fórmula de Backoff

sleep = random(0, min(cap_ms, base_ms × 2^attempt))

base_ms = 250, cap_ms = 30,000

Intento 1:
0-500ms
Intento 2:
0-1000ms
Intento 3:
0-2000ms
Intento 4:
0-4000ms
Intento 5:
0-8000ms

Manejo de HTTP 404

HTTP 404 responses are handled locally per endpoint, NOT as a global error classification. For EP-2 (getDetailByNo): 404 triggers a negative cache (TTL=60s, max 1024 entries). A sliding window tracker (threshold=2, window=600s) can mark an ad as "permanently dead" after 3600s of persistent 404 responses.

Error 187049: La Solución de Solo Precio

El error más frecuente en el desarrollo con la API C2C de Binance. Ocurre cuando surplusAmount se envía junto con price en una actualización de anuncio. Binance valida el surplus contra un valor en caché que puede haber cambiado debido a operaciones activas.

Solución: Envía SOLO advNo + price al actualizar el precio.

Ver EP-7: Update Ad para todos los detalles.

Todos los Códigos de Error

CódigoNombreCategoríaEnv Var
-1021Timestamp out of recvWindowRETRY_WITH_SYNC
-1022Invalid signatureRETRY_WITH_SYNC
-1000Unknown errorRETRIABLE_WITH_BACKOFF
-9000System error (wrapper)RETRIABLE_WITH_BACKOFF
-1102Mandatory parameter missingNON_RETRIABLE_BUSINESS
-1104Unknown parameterNON_RETRIABLE_BUSINESS
187049Ad status errorRETRY_WITH_VOLUME_SYNC
187040Ad status error (variant)RETRY_WITH_VOLUME_SYNC
187031Ad update failedRETRY_WITH_VOLUME_SYNC
187055Price overlapSPECIAL_HANDLER
-2019Margin insufficientNON_RETRIABLE_BUSINESS
-2015Invalid API key/permissionsNON_RETRIABLE_BUSINESS
-3026Order already completedNON_RETRIABLE_BUSINESS
-1013Invalid quantityNON_RETRIABLE_BUSINESS
-1111Precision over maximumNON_RETRIABLE_BUSINESS
83229Business closedAD_OFFLINE
83230Taking a breakAD_OFFLINE