Puntos clave
- El texto proviene del cliente, así que reproduce la llamada con curl para ver el cuerpo de error real y el estado.
- HTTP 429 con código rate_limited o concurrency es la causa más común en una cuenta ocupada, y un flujo mantiene su ranura hasta que termina.
- Verifica la URL base, la clave, el ID del modelo uncensored, el tamaño del cuerpo (8 MB) y los tokens totales (100,000) antes de cualquier otra cosa.
- Reintenta solo 429 y caídas de red, espera por Retry-After, y mantén la concurrencia por debajo del límite de la clave.
Lo que realmente te dice el mensaje
Si buscaste error desconocido del flujo LLM, probablemente estés viendo un toast o una línea roja en un front-end de chat, un plugin de editor o un framework de agente. La redacción proviene de ese cliente. Significa que la app solicitó una respuesta en streaming, algo salió mal antes o durante el flujo, y la app no supo cómo describirlo. La API en sí informa problemas con un estado HTTP y un cuerpo de error JSON, y el cliente ha desechado ese detalle.
Esa es buena noticia, porque significa que puedes recuperar el detalle. Envía la misma solicitud fuera del cliente, lee la línea de estado y el cuerpo, y la causa suele ser obvia en uno o dos intentos. El resto de esta página recorre las causas en el orden en que tienden a ocurrir en esta API, luego te da un pequeño cliente de streaming que imprime el error real en lugar de ocultarlo.
Una cosa a tener en cuenta desde el principio: una petición en streaming tiene dos puntos de fallo. Puede fallar antes del primer byte, cuando el servidor rechaza la petición (clave mala, URL mala, un límite). O puede fallar en el medio, cuando la conexión se cae después de que ya haya llegado algo de texto. Las soluciones difieren, así que nota cuál de los dos ves. Si la respuesta nunca comienza, mira las secciones dos a cuatro. Si comienza y luego se detiene, mira la sección sobre proxies y tiempos de espera.
Verifica primero la URL base, la clave y el modelo
La mayoría de los errores de streaming en una configuración nueva provienen de tres pequeños errores. Toman un minuto descartarlos.
- URL base. Debe ser
https://api.uncensoredllmhub.com/v1, incluyendo/v1y sin un/chat/completionsal final. Los clientes añaden la ruta ellos mismos. Si pegas el endpoint completo en un campo que espera una base, el cliente solicita una ruta que no existe e informa un fallo vago. - Clave. El encabezado es
Authorization: Bearer YOUR_KEY. Un espacio extra, una nueva línea copiada con la clave, o una clave de otro servicio fallan de la misma manera. Crea o copia la clave nuevamente desde la página de clave de API si no estás seguro. - ID del modelo. El único modelo es
uncensored. Los clientes que ofrecen un menú desplegable a menudo rellenan automáticamente un nombre de otro proveedor. Escribe el ID a mano, y llama aGET /v1/modelssi quieres confirmar qué lista el servidor.
Una forma rápida de probar los tres a la vez es la llamada models. No hace streaming, así que separa un problema de conexión o clave de un problema de streaming:
curl -i https://api.uncensoredllmhub.com/v1/models -H "Authorization: Bearer $API_KEY"
Si esto devuelve una lista normal, la URL y la clave están bien y puedes dejar de sospechar de ellas. Si falla, corrígelo antes de tocar nada relacionado con streaming. También comprueba que tu cuenta tenga crédito: la API envía tu saldo restante en el encabezado X-Balance-USD de las respuestas, lo cual es útil cuando una clave deja de funcionar de repente tras un uso intensivo. La página de precios explica las recargas, y las cuentas nuevas pueden reclamar un crédito de prueba de $0.50 desde la página de claves.
Límites de velocidad y el flujo que mantiene su ranura
La siguiente causa más común es HTTP 429. Hay tres variantes, y tu cliente las agrupará todas en el mismo mensaje poco útil.
| Señal | Significado | Qué hacer |
|---|---|---|
429, código rate_limited | Demasiadas peticiones por minuto para la clave | Ralentiza; una clave completa permite 300 por minuto, una clave de prueba 60 |
429, código concurrency | Demasiadas peticiones simultáneas | Encola las peticiones; una clave completa permite 8 a la vez, una clave de prueba 2 |
429 con Retry-After: 5 | Sobrecarga temporal en el lado del servicio | Espera 5 segundos y vuelve a intentar |
El límite de concurrencia es el que más sorprende a la gente, debido a cómo funciona streaming. Una petición en streaming ocupa su espacio hasta que termina el flujo, no hasta que llega el primer token. Si tu aplicación abre un flujo para cada mensaje y nunca cierra el anterior, por ejemplo porque el usuario navegó a otra parte y la interfaz olvidó cancelar la petición, esos espacios permanecen ocupados. En una clave de prueba con un límite de 2, dos flujos abandonados son suficientes para que falle el tercer mensaje.
Los síntomas son consistentes. Los primeros mensajes funcionan, luego empiezan los errores, y luego todo vuelve a funcionar tras una breve espera. Si eso coincide, aborta los flujos que ya no necesites (un AbortController en el navegador, cerrando la respuesta en un servidor) y limita el número de peticiones simultáneas en tu propio código. Los agentes son los principales culpables: un planificador que lance diez llamadas a funciones a la vez alcanzará el límite en una clave de prueba inmediatamente.
Los encabezados de respuesta te ayudan a ver dónde estás. X-RateLimit-Limit-Requests y X-RateLimit-Limit-Concurrency muestran los límites que aplican a la clave que usaste, y X-Request-Id identifica la llamada si necesitas preguntar a soporte sobre ello.
Tamaño de la petición y longitud del contexto
Una petición también puede ser rechazada por ser demasiado grande. Dos números importan. El cuerpo puede ser de máximo 8 MB, y el prompt más la completación deben caber en una ventana de contexto de 100,000 tokens. Los front-ends de chat que reenvían toda la conversación en cada turno alcanzan estos límites lentamente y luego todos a la vez: el chat funciona durante una hora, luego un mensaje largo o un archivo pegado lo supera, y cada turno posterior falla porque el historial sigue estando en la petición.
Si el error comienza después de una sesión larga, prueba con una conversación nueva corta. Si eso funciona, el historial es la causa. Recórtalo eliminando turnos antiguos, resumiéndolos en un mensaje, o iniciando un chat nuevo. Los documentos grandes pegados son otro desencadenante. Un archivo de texto de unos pocos cientos de kilobytes está bien, pero los blobs base64 o registros muy grandes pueden alcanzar 8 MB más rápido de lo que esperas.
No tienes que establecer max_tokens, ya que la completación puede usar lo que quede de la ventana. Si lo estableces, asegúrate de que los tokens del prompt más max_tokens se mantengan por debajo de 100,000. Un cliente que codifica en duro un max_tokens grande encima de un historial largo puede empujar la suma por encima de la ventana incluso cuando el prompt solo parece estar bien.
Proxies, almacenamiento en búfer y tiempos de espera
El streaming usa eventos enviados por el servidor: una respuesta HTTP de larga duración que envía pequeños fragmentos a medida que se generan. Cualquier cosa entre tú y la API que espere a toda la respuesta antes de reenviarla lo romperá. El resultado es ya sea un largo silencio seguido de una ráfaga, o un tiempo de espera y el error genérico.
Busca estos en tu propia configuración:
- Proxies inversos. Si enrutas la API a través de nginx o un proxy similar, desactiva el almacenamiento en búfer de respuesta para esa ubicación, y sube el tiempo de espera de lectura por encima de la respuesta más larga que esperes. Las respuestas largas de una ventana de 100,000 tokens pueden tardar un poco.
- Proxies corporativos o de antivirus. Algunos inspeccionan el tráfico HTTPS y retienen el cuerpo. Prueba desde un punto de acceso de teléfono para descartar esto.
- Funciones sin servidor. Muchas plataformas limitan el tiempo de ejecución o almacenan en búfer las respuestas a menos que optes por el streaming. Si el flujo se corta al mismo número de segundos cada vez, un límite de tiempo de la plataforma es la causa probable.
- Extensiones del navegador y VPN. Raro, pero pueden cortar conexiones inactivas.
La pista que apunta aquí es un error en medio de una respuesta, con el mismo tiempo de corte en cada intento. Un límite de velocidad rechazaría la petición al principio, así que un corte en medio del flujo que siempre ocurre, por ejemplo, a los 30 segundos, casi nunca es un límite.
Un cliente que muestra el error real
Usa esto cuando quieras la verdad en lugar del mensaje amigable. Captura las excepciones del SDK de OpenAI, imprime el estado y el cuerpo de error, y lee la pista de reintento cuando haya una.
import time
from openai import OpenAI, APIConnectionError, APIStatusError, RateLimitError
client = OpenAI(
base_url="https://api.uncensoredllmhub.com/v1",
api_key="YOUR_API_KEY",
)
def stream_once(messages):
stream = client.chat.completions.create(
model="uncensored",
messages=messages,
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
if getattr(chunk, "usage", None):
print("\n[usage]", chunk.usage)
messages = [{"role": "user", "content": "Write two sentences about harbours."}]
for attempt in range(4):
try:
stream_once(messages)
break
except RateLimitError as e:
wait = int(e.response.headers.get("retry-after", 5))
print("429:", e.body, "- waiting", wait, "s")
time.sleep(wait)
except APIStatusError as e:
print("status", e.status_code, e.body)
print("request id:", e.response.headers.get("x-request-id"))
break
except APIConnectionError as e:
print("connection problem:", e)
time.sleep(2)
La misma idea en Node, con una señal de aborto para que los flujos abandonados liberen su ranura:
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.uncensoredllmhub.com/v1",
apiKey: process.env.API_KEY,
});
const controller = new AbortController();
try {
const stream = await client.chat.completions.create(
{
model: "uncensored",
messages: [{ role: "user", content: "Write two sentences about harbours." }],
stream: true,
},
{ signal: controller.signal }
);
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}
} catch (err) {
console.error("status:", err.status, "body:", err.error);
}
// call controller.abort() when the user leaves the page
Y una llamada curl cruda, que elimina cada cliente de la ecuación. -N desactiva el almacenamiento en búfer propio de curl y -i imprime la línea de estado y los encabezados, incluyendo X-Request-Id:
curl -N -i https://api.uncensoredllmhub.com/v1/chat/completions -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" -d '{"model":"uncensored","stream":true,"messages":[{"role":"user","content":"Say hello."}]}'
Si curl transmite texto bien y tu app no, la API está sana y el problema está en la app, su proxy o su configuración. Si curl muestra un 429 u otro estado, ahora tienes la causa exacta.
Reglas de reintento que no empeoran las cosas
Los reintentos ayudan con problemas transitorios y dañan con problemas permanentes. Una política corta te mantiene fuera de problemas.
- Reintenta 429 y conexiones caídas. Espera por
Retry-Aftercuando esté presente, de lo contrario espera unos segundos y añade algo de jitter aleatorio para que los trabajadores paralelos no reintenten al mismo tiempo. - No reintentes fallos de autenticación o peticiones demasiado grandes. El resultado no cambiará, y cada reintento solo añade ruido.
- Limita los intentos a tres o cuatro, luego muestra al usuario el texto de error real.
- Limita tu propia paralelismo por debajo del límite de la clave. Un semáforo de 6 en una clave completa deja espacio para una segunda herramienta usando la misma clave.
- Si un flujo se rompe a mitad de camino, conserva el texto parcial. Reenvía con ese texto como un mensaje del asistente y pide al modelo que continúe, en lugar de regenerar desde cero.
Las peticiones fallidas o rechazadas no se cobran, así que depurar con llamadas de prueba repetidas no drena tu crédito. Las llamadas exitosas se facturan a $0.15 por 1M de tokens de entrada y $0.50 por 1M de tokens de salida, y un flujo parcial que se completa normalmente es simplemente una respuesta corta. Más detalles sobre el formato de la petición están en la documentación de API.
Si has hecho todo lo anterior y aún ves el mensaje, envía el X-Request-Id de una llamada fallida a la página de soporte, con la hora del intento y si el fallo vino antes o después del primer token. Esa información es suficiente para rastrear lo que sucedió.
