ES ▾
Obtener clave de API

Guía de códigos de error y resolución de problemas de la API sin censura

No temes los errores, sino no saber si reintentar o cambiar el código. Esta guía desglosa cada código de estado: condiciones, criterios y solución. El cuerpo del error es JSON con code y message; lee el body, no solo el código. Incluye reintentos con retroceso exponencial, límite de velocidad y lista de verificación.

Actualizado el

Puntos clave

  • Solo 429 y 503 valen la pena para reintentos automáticos; reintentar otros códigos desperdicia peticiones.
  • 402 no_credit es saldo agotado o prueba expirada; 403 content_blocked es contenido bloqueado. No son problemas de red.
  • Los reintentos deben usar retroceso exponencial con jitter y un número máximo de intentos.
  • 300 peticiones por minuto por clave; limita la velocidad en el cliente para tareas por lotes.

Formato del cuerpo de error y orden de lectura

Todas las respuestas fallidas tienen la misma estructura:

{"error":{"code":"...","message":"..."}}

El orden de lectura tiene tres pasos fijos:

  1. Código de estado HTTP, para la categoría;
  2. error.code indica la causa específica; úsalo para hacer ramificación en el código;
  3. error.message, para humanos y logs, no para coincidencia de cadenas.

Define primero la frontera: los que se resuelven con reintento (429, 503 y timeout de red) y los que requieren cambio (el resto). Mezclarlos es la causa raíz más común de incidentes, como reintentar 402 y generar docenas de peticiones inválidas por segundo.

Registra siempre cuatro campos: hora, código de estado, error.code y el valor estimado de prompt_tokens de la petición. Así verás si aumentan errores específicos o si falla todo. Configura una alerta: 402 notifica al instante porque indica servicio no disponible; 429 evalúa la proporción: si es esporádico, ignóralo; si es continuo, hay un problema de concurrencia.

Búsqueda rápida de códigos de estado

Código de estadoerror.codeSignificado¿Reintentar?
400—Petición inválida, ej. prompt + max_tokens > 100kNo
401—Clave inválida o ausenteNo
402no_creditSaldo agotado o prueba expiradaNo
403content_blockedContenido bloqueadoNo
404—Endpoint no encontradoNo
429—Límite de peticiones excedidoSí, con retroceso
503upstream_busyServicio ocupado temporalmenteSí, en unos segundos

El «—» indica que no hay un código de cadena fijo que requiera manejo especial; usa la ramificación por código de estado.

4xx: Cambia la petición, no reintentar

400 Petición inválida

  • Causa 1: Error de formato JSON, común al construir cadenas a mano sin escapar las comillas.
  • Causa 2: prompt + max_tokens superan 100,000. Es lo más fácil de activar en conversaciones largas.
  • Causa 3: Cuerpo de petición > 8 MB.
  • Solución: serializa con una librería JSON; estima los tokens antes de enviar y, si excedes la ventana de contexto, recorta el historial o reduce max_tokens; consulta contexto largo.

401 Problemas con la clave

  • Falta el Header o el prefijo Bearer .
  • Regeneraste la clave; la antigua caducó pero un servidor aún la usa.
  • La variable de entorno no se pasó al contenedor o tarea programada.

402 no_credit

Se agotó el saldo o la prueba de 7 días ha expirado. Ve a la página de tu cuenta para recargar el saldo prepago y reanudar. Te recomendamos monitorear el saldo de tu servicio para que no te sorprendan los errores de los usuarios.

403 content_blocked

Contenido bloqueado. El contenido adulto legítimo, la ficción y los temas controvertidos no se rechazan, pero el contenido sexual que involucra a menores se bloquea siempre, tanto en novelas como en roleplay. Si obtienes un 403, revisa si el prompt o el historial contienen este tipo de contenido; no cambies las palabras e intentes de nuevo.

404 endpoint no encontrado

Solo hay dos endpoints: POST /v1/chat/completions y GET /v1/models. Una ruta incorrecta (falta /v1, sobra una barra, error de ortografía) o solicitar endpoints no soportados como embeddings o imágenes provocará un 404.

Otro error 400 fácil de malinterpretar: los tokens de un diálogo largo crecen linealmente con las rondas. Todo funciona bien durante las pruebas diurnas, pero tras decenas de rondas empiezan a aparecer 400. No es inestabilidad de la API, es que se ha alcanzado la ventana de contexto. La solución es limitar el historial: descartar las rondas más antiguas al superar un umbral o resumir el contenido antiguo. No esperes al error para gestionarlo; estima el consumo antes de enviar la petición.

Un truco para depurar 401: imprime en los logs los cuatro primeros y los cuatro últimos caracteres de la clave, no el contenido completo, y compáralo con lo que muestra la página de tu cuenta. Así confirmas si el proceso está leyendo la clave que crees, algo crucial en entornos de contenedores o tareas programadas donde la variable de entorno puede faltar o contener un valor antiguo.

429 y 503: los dos errores que sí requieren reintentos

429 límite de peticiones

300 peticiones por minuto y por clave. Las tareas por lotes, el uso compartido de una clave entre múltiples instancias y las tormentas de reintentos pueden activarlo. La corrección tiene dos capas: primero limita las peticiones desde el cliente (ver código más abajo) y luego aplica reintentos con retroceso ante un 429.

503 upstream_busy

El servicio está temporalmente ocupado; reintenta tras unos segundos. No envíes peticiones en cascada ni reintentes diez veces en un segundo, ya que solo empeorarás la situación.

Tiempo de espera de red

La generación de texto largo lleva tiempo; no configures un timeout demasiado corto, usa 120 segundos como ejemplo. Ten cuidado al reintentar tras un timeout: la petición original puede haberse ejecutado en el servidor, por lo que una llamada duplicada podría consumir saldo dos veces. Para peticiones de generación, reduce el número de reintentos y, de ser posible, usa streaming para acortar la espera.

import os
import random
import time
import requests

URL = "https://api.wushenchaapi.com/v1/chat/completions"
HEADERS = {
    "Authorization": "Bearer " + os.environ["API_KEY"],
    "Content-Type": "application/json",
}
RETRYABLE = {429, 503}          # 只重试这两类
FATAL = {400, 401, 402, 403, 404}

class ApiError(Exception):
    def __init__(self, status, code, message):
        super().__init__(f"{status} {code}: {message}")
        self.status, self.code = status, code

def call(payload, max_retries=5, base=1.0, cap=30.0):
    for attempt in range(max_retries + 1):
        try:
            r = requests.post(URL, headers=HEADERS, json=payload, timeout=120)
        except (requests.ConnectionError, requests.Timeout):
            r = None                      # 网络层失败,按可重试处理
        if r is not None and r.ok:
            return r.json()
        if r is not None:
            try:
                err = r.json().get("error", {})
            except ValueError:
                err = {}
            if r.status_code in FATAL or r.status_code not in RETRYABLE:
                raise ApiError(r.status_code, err.get("code"), err.get("message"))
        if attempt == max_retries:
            raise ApiError(r.status_code if r is not None else 0, "retry_exhausted", "重试次数用尽")
        delay = min(cap, base * (2 ** attempt)) * random.uniform(0.5, 1.0)
        time.sleep(delay)

if __name__ == "__main__":
    out = call({"model": "uncensored", "max_tokens": 100,
                "messages": [{"role": "user", "content": "回复一个字:好"}]})
    print(out["choices"][0]["message"]["content"])

Clave: la fórmula de retroceso es min(cap, base × 2^n) × factor aleatorio; el jitter aleatorio evita que múltiples clientes reintenten al mismo tiempo y colisionen. No reintentes nunca los códigos de estado de la colección FATAL.

Límite de peticiones y peticiones de diagnóstico en el cliente

En lugar de esperar a un 429 para aplicar retroceso, es mejor limitar las peticiones de antemano. La siguiente herramienta garantiza que el número de peticiones por minuto no supere un valor establecido, con seguridad para hilos múltiples:

import threading
import time

class RateGate:
    """简单的客户端限速:保证一分钟内请求数不超过 limit。"""
    def __init__(self, limit=240):          # 留出余量,低于 300/分钟
        self.limit, self.stamps, self.lock = limit, [], threading.Lock()

    def wait(self):
        while True:
            with self.lock:
                now = time.time()
                self.stamps = [t for t in self.stamps if now - t < 60]
                if len(self.stamps) < self.limit:
                    self.stamps.append(now)
                    return
                sleep_for = 60 - (now - self.stamps[0])
            time.sleep(max(sleep_for, 0.05))

Para depurar, la forma más limpia es aislarte del código de negocio y enviar una petición mínima con curl. Usa -i para ver simultáneamente la línea de estado y los encabezados de respuesta:

curl -i https://api.wushenchaapi.com/v1/chat/completions \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"uncensored","max_tokens":20,"messages":[{"role":"user","content":"ping"}]}'

Si curl funciona pero tu código de negocio falla, el problema está en tu código o entorno (proxy, variables de entorno, codificación). Si curl tampoco funciona, revisa la clave, el saldo y la red.

Por qué el límite es 240 y no 300: en despliegues con múltiples instancias, cada una aplica su propio límite y la suma puede aún superar el límite total; además, los reintentos consumen cuota extra. Deja un 20 % de margen. Si tienes varias instancias, reparte el total equitativamente o usa un contador compartido.

Lista de verificación para solucionar problemas

  1. Lee el campo error.code del body, no te limites a ver el código de estado.
  2. 401: prefijo de la clave, variables de entorno, si se ha regenerado.
  3. 400: ¿Es JSON válido? ¿prompt + max_tokens superan 100,000? ¿El cuerpo de la petición supera 8 MB?
  4. 402: Saldo y validez de la prueba.
  5. 403: si el prompt o el historial contienen contenido prohibido.
  6. 404: si la ruta es /v1/chat/completions o /v1/models.
  7. 429: si varias instancias comparten una clave, si se aplica límite de peticiones en el cliente.
  8. 503: si se aplica retroceso con reintentos y el intervalo es de al menos varios segundos.
  9. Timeout: si el tiempo de espera es suficiente, si puedes cambiar a streaming.
  10. Si se descartan todas las anteriores: reproduce el error con una petición mínima en curl.

Si acabas de empezar, consulta primero el tutorial de integración. Más parámetros están en la documentación.

Uso de la lista: descarta problemas de arriba a abajo, sin saltarte pasos. La mayoría de las fallas «extrañas» terminan siendo una de las primeras cuatro.

Un consejo adicional: escribe las conclusiones de cada depuración en la documentación del equipo. Así, la próxima vez que aparezca el mismo error, podrás identificarlo de inmediato.

Preguntas frecuentes

¿Cuánto hay que esperar para reintentar tras un 503?

Espera unos segundos. Espera 1-2 s la primera vez, aumenta exponencialmente, añade jitter y fija un máximo de reintentos.

¿Por qué mis peticiones devuelven siempre 402?

Saldo agotado o caducada la prueba de 7 días. Recarga el saldo prepago para recuperar el acceso; el saldo no caduca.

¿Se puede evitar un 403 content_blocked cambiando el texto?

No lo intentes. El contenido sexual con menores se bloquea siempre, incluso en novelas y roleplay. El contenido adulto normal no activa este error.

¿El 429 se limita por cuenta o por clave?

El límite es de 300 peticiones por minuto por clave. Cada cuenta tiene una clave, así que coordina el límite de peticiones si varios servicios la comparten.

Completa el formulario para obtener tu clave

Crea una cuenta, copia la clave y modifica la Base URL. La configuración es así de sencilla.