> This page is for De cámara a la nube.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://next.developer.frame.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://next.developer.frame.io/_mcp/server.

# Guía práctica: Gestionar errores

## Introducción





En esta guía se trata la gestión de errores al interactuar con la API de C2C. Gestionar adecuadamente los errores HTTP es una parte esencial de una integración sólida con cualquier servicio de terceros.





## Tipos de errores





Los errores en su integración pueden proceder de varias fuentes, que podemos categorizar en cuatro grupos principales:




* **Errores de E/S:** Proceden de operaciones de hardware en su dispositivo, como operaciones de lectura/escritura fallidas
* **Errores de la aplicación:** Surgen de problemas con el código de su aplicación
* **Errores de red:** Ocurren dentro de la pila de red y su biblioteca de redes informa de ellos
* **Errores de la API:** Generados por los servicios de backend de Frame.io




Cada categoría de error debe gestionarse de maneras concretas. Esta guía se centra principalmente en los errores de la API, aunque también abordaremos estrategias generales para las otras categorías.





## Cómo se devuelven los errores de la API





La API de Frame.io comunica los errores mediante dos mecanismos principales:




* **Códigos de estado:** Códigos de error HTTP que indican la naturaleza del problema
* **Mensajes de error:** Contenido de carga útil que proporciona detalles adicionales sobre el error, especialmente cuando varias condiciones de error comparten el mismo código de estado




### Códigos de estado de error

Los códigos de estado HTTP son respuestas numéricas estandarizadas que comunican el resultado de una solicitud HTTP. Para obtener más información, consulte la [documentación de los códigos de estado HTTP de Mozilla](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) o [HTTP Cats](https://http.cat/) para disfrutar de un enfoque más visual. Cada punto final de la API de Frame.io especifica un código de estado de éxito esperado, normalmente `200 (OK)`, `201 (Created)` o `204 (No Content)`. Puede verificar el éxito comprobando estos códigos específicos o confirmando que el código se encuentra dentro del rango 200-299. Los códigos de estado por encima de 399 indican errores. La mayoría de los errores de la API devuelven códigos 4XX (400-499), que hacen referencia a problemas del lado del cliente. Los errores fuera de este rango suelen proceder de la infraestructura de red entre su dispositivo y nuestro servicio, con la notable excepción de `500 (Internal Server Error)`, que indica un problema inesperado en nuestro servidor. Del mismo modo, una respuesta `404 (Not Found)` podrían generarla servicios intermedios en lugar de nuestro backend, a pesar de ser un código 4XX.

Si se encuentra con códigos de estado inesperados, póngase en contacto con nuestro equipo.





### Esquemas de carga útil de error





Frame.io devuelve los detalles de los errores en dos formatos: *sencillo* y *detallado*. Su lógica de gestión de errores debe acomodar ambos formatos.





### Esquema de error sencillo

A continuación, se muestra un ejemplo de una solicitud fallida con un `client_secret` incorrecto:

```shell
curl -X POST https://api.frame.io/v2/auth/device/code \
    --include \
    --header 'x-client-version: 2.0.0' \
    --form 'client_id=Some-Client-ID' \
    --form 'client_secret=bad_secret' \
    --form 'scope=asset_create offline'
```





Respuesta:





```text
HTTP/2 400
...

{"error":"invalid_client"}
```





El esquema sencillo contiene un único campo para identificar el error.





### Esquema de error detallado





Para comparar, a continuación se muestra una solicitud sin autorización adecuada:





```shell
curl -X POST https://api.frame.io/v2/devices/heartbeat \
    --header 'Authorization: Bearer bad-token' \
    --header 'x-client-version: 2.0.0' \
    | python -m json.tool
```





Respuesta:





```json
{
    "code": 409,
    "errors": [
        {
            "code": 409,
            "detail": "The channel you're uploading from is currently paused.",
            "status": 409,
            "title": "Channel Paused"
        }
    ],
    "message": "Channel Paused"
}
```

Los errores detallados contienen un campo `message` que identifica el tipo de error.

### Determinar el tipo de error





Al gestionar errores de Frame.io, primero compruebe si hay una carga útil de error y, si no la hay, consulte el código de estado HTTP.





A continuación, se muestra una implementación básica de la gestión de errores:





**`Python`**

```python title="Python"
# Dict of known error codes: native errors.
ERROR_STATUS_MAP = {
    429: SlowDownError,
    ...
}

# Dict of known error messages: native errros.
ERROR_MESSAGE_MAP = {
   "Channel Paused": ChannelPausedError,
   "invalid_client": InvalidClientError,
   "slow_down": SlowDownError,
   ...
}

def _c2c_extract_error_message(response):
    """
    Gets the error message from an error payload. Returns `None` 
    if an error payload is not found.
    """

    # Try to decode the payload, if it is not JSON return `None`
    try:
        payload = response.json() 
    except JSONDecodeError:
       return None

    # Try the simple error schema first.
    message = payload.get("error", default=None)
    if message is not None:
        return message

    # Now try the detailed schema. Return None if we do not find one.
    return payload.get("message", default=None)

def _c2c_error_type_from_response(response):
    """
    Converts a bad HTTP response into an error.
    """
    error_message = _c2c_extract_error_message(response)

    # try to do a lookup of the error type by message.
    error_type = ERROR_MESSAGE_MAP.get(error_message, default=None) 
    if error_type is not None:
        return error_type()

    # If not, try to do a lookup by error code.
    error_type = ERROR_STATUS_MAP.get(response.status_code, default=None)
    if error_type is not None:
        return error_type()

    # Otherwise we are going to return an `UnknownAPIError` to signal that we
    # encoutnered an error from Frame.io's backend servers, but do not know the
    # message and/or status code.
    return UnknownAPIError(message=error_message)

def raise_on_frameio_error(response, expected_status):
    """
    Raises a native error from an HTTP response if the response indicates an error
    occured. Expected status should be the status we expect to get (200, 201, 204, 
    etc).
    """

    # If the status code is less than `400`, then it is not an error status code.
    if response.status < 400:

        # Check that the status code is the one we expected, otherwise raise an
        # error.
        if response.status != expected_status:
            raise UnexpectedStatusError(
                expected=expected_status, received=response.status
            )

        return None

    # Otherwise convert and raise a native error.
    raise _c2c_error_type_from_response(response)
```





Las tablas de búsqueda de errores a las que se hace referencia en este ejemplo se proporcionan al final de esta guía.





### Errores de AWS

Al cargar fragmentos de archivos, interactúa directamente con AWS S3, que tiene su propio formato de error. Consulte la [documentación de errores comunes de AWS](https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html#ErrorCodeList) para obtener más detalles. Como regla general, los errores no graves de AWS deben volver a intentarse al menos una vez.

Los errores de AWS se devuelven en formato XML:





```xml
<?xml version="1.0" encoding="UTF-8"?>
<Error>
  <Code>NoSuchKey</Code>
  <Message>The resource you requested does not exist</Message>
  <Resource>/mybucket/myfoto.jpg</Resource> 
  <RequestId>4442587FB7D0A2F9</RequestId>
</Error>
```

El elemento `Code` identifica el tipo de error.

## Volver a intentar errores





### Cuándo reintentarlo

Las tablas de error de esta guía indican qué errores de la API se deben reintentar. Para errores que no son de la API de operaciones de E/S, bibliotecas de red o AWS, plantéese reintentar aquellos que puedan ser el resultado de condiciones transitorias. La congestión de la red, las interrupciones temporales del servidor o la pérdida de paquetes normalmente justifican reintentos. La mayoría de las bibliotecas de red generan `TimeoutError` cuando una solicitud tarda demasiado, que es uno de los principales motivos para realizar un reintento.

### En caso de duda, reintente una vez

Los entornos informáticos pueden experimentar problemas impredecibles. Incluso con errores que parecen graves, a menudo vale la pena hacer un reintento. Los estados temporales del sistema, las anomalías de hardware (como [inversiones de bits causadas por rayos cósmicos](https://www.youtube.com/watch?v=AaZ_RSt0KP8)) o condiciones raras de la memoria pueden provocar errores aparentemente graves que se resuelven en un segundo intento. Sin embargo, algunos errores no se deben reintentar. Por ejemplo, una respuesta `409: CHANNEL PAUSED` al crear un activo indica que el dispositivo está en pausa y no debería realizar ninguna carga. Este estado es deliberado y es poco probable que cambie con un reintento.

### Espera exponencial

Frame.io implementa límites de frecuencia, y exceder estos límites produce un error `429: Slow Down` o un estado `400` con esta carga útil:

```text
HTTP/2 400

{"error":"slow_down"}
```





Cuando reciba estas respuestas, implemente una espera exponencial para los reintentos. Una fórmula recomendada para calcular el retraso (en segundos) es:





**`Python`**

```python title="Python"
delay = min(2 ** attempt / 2, 32.0)
```

Donde `attempt` comienza en 0. Esto produce retrasos de 0,5, 1, 2, 4, 8, 16 y 32 segundos, de forma que todos los intentos posteriores esperan 32 segundos.
<Info title="Fluctuación de la espera">
  Recomendamos añadir aleatoriedad (fluctuación) a su tiempo de espera para evitar que se sincronicen las solicitudes en varios dispositivos que se recuperan de la misma condición de error. Esto ayuda a mitigar el [problema de la estampida](https://medium.com/@venkteshsubramaniam/the-thundering-herd-distributed-systems-rate-limiting-9128d20e1f00), donde muchos dispositivos reintentan simultáneamente tras una interrupción. Un buen enfoque consiste en añadir un desplazamiento aleatorio entre 0 y la mitad del retraso calculado: `math.rand(0, delay // 2)`.
</Info>


La espera exponencial no solo es esencial para errores de limitación de velocidad, sino que también tiene ventajas a la hora de gestionar fallos de red y E/S en general. Este enfoque permite que las restricciones temporales para los recursos se resuelvan sin carga adicional de sus reintentos.





### Detectar el estado de desconexión





Cuando se producen errores de red, pueden indicar que no se puede acceder a Frame.io por los siguientes motivos:




* La red local no funciona
* Los servicios de Frame.io están teniendo problemas
* Un componente de red intermedio está fallando




Es importante detectar estas condiciones. Cuando un error sugiere problemas de conectividad, implemente una tarea de monitorización que compruebe la restauración del servicio e informe al usuario de la desconexión.





### Esperar por la conexión y autorización





Diseñe su aplicación para evitar realizar solicitudes innecesarias cuando el dispositivo actualice la autorización, espere por la autorización del usuario o no pueda acceder a Frame.io. Esto reduce la sobrecarga de la red y mejora la experiencia del usuario.

Bloquee todas las llamadas API (excepto a `https://api.frame.io/health`) cuando detecte un estado de desconexión. Cuando haya problemas de conectividad, inicie una tarea en segundo plano que sondee el punto final de estado y bloquee las llamadas API adicionales hasta que se restaure la conectividad.

De manera similar, si el token caduca, bloquee las llamadas que dependan de la autorización hasta que se emita uno nuevo. Si la actualización del token falla, alerte al usuario para que se vuelva a autenticar.





Al sondear el estado de conexión, aplique el mismo enfoque de espera exponencial descrito anteriormente.





### Tiempos de espera de las solicitudes





Configure valores de tiempo de espera apropiados para diferentes tipos de solicitudes:




* **Predeterminado**: 15 segundos para las solicitudes básicas
* **Actualización de autorización**: 2 minutos para tener en cuenta el posible procesamiento del backend
* **Carga de fragmento de archivo**: 5 minutos para adaptarse a redes lentas al transferir datos de mayor tamaño




### Ejemplo de controlador de reintentos





A continuación, se muestra una implementación de pseudocódigo que muestra la gestión de errores con espera exponencial:





**`Python`**

```python title="Python"
# List of errors we know are fatal and should not be retried.
FATAL_ERRORS = (
    ChannelPausedError,
    DevicesDisabledError,
    ...
)

# List of errors we know should be retried more than once.
RETRY_ERRORS = (
    TimeoutError,
    NotFoundError,
    SlowDownError,
    UnknownAPIError,
    ...
)

# List of errors that could be the result of Frame.io being unreachable.
DISCONNECTED_ERRORS = (
    TimeoutError,
    HttpClientError,
    ...
)

def retry_with_backoff(next_handler):
    """
    Middleware for retrying errors with exponential backoff.
    """

    def retry_handler(call, retry_count):
        """
        Handler for retrying c2c API calls with exponential backoff.
        """

        error = None

        # We will retry the call 8 times here, totalling 63.5 seconds +- ~32 seconds.
        for attempt in range(start=1, stop=retry_count + 1):

            # If we are attempting to reach an endpoint that requires authorization
            # we should wait unil we have valid authorization before attempting
            # a call. We need to do this each time in case our access_token
            # expires between attempts.
            C2C.wait_for_authorized(call)

            # Likewise, we should wait until we are connected to Frame.io to attempt
            # a call if we are not calling `https://api.frame.io/health`
            C2C.wait_for_connected(call)

            try:
                # Return the result on a success.
                return next_handler(call)
            except FATAL_ERRORS as error:
                # If we hit an error we know is fatal, raise the error without
                # retrying it.
                raise error

            except RETRY_ERRORS as error:
                # If we hit an error we know we should retry many times, continue,
                # but notify our client if we think we may have been disconnected.
                if type(error) in DISCONNECTED_ERRORS:
                    C2C.notify_disconnected()

            except BaseException as error:
                # Otherwise, do not retry the call more than once.
                if attempt > 1:
                    raise error

            # The delay for the next attempt should be no more than 32 seconds.
            # This algorithm will go: 0.5s, 1s, 2s, 4s, 8s, 16s, 32s, 32s, ...
            delay = min(2 ** attempt / 2, 32.0)

            # Add some randomness (jitter) to the delay (up to half the value of
            # the delay in either direction).
            delay += math.random(-delay, delay) / 2

            # Wait between retries
            sleep(delay)

        # If we have exhausted all retries,
        raise error

    return retry_handler
```





## Tablas de errores





En las siguientes tablas se categorizan los errores de la API de Frame.io y se proporciona orientación para gestionarlos. Esto es lo que representa cada columna:

`Mensaje`: El identificador del mensaje de carga útil del error. `Código HTTP`: El código de estado HTTP. `Tipo de error`: Una categoría conceptual del error (se describe en la sección [Descripciones](#descriptions)). `Esquema`: El formato de carga útil del error ([sencillo](#simple-error-schema) o [detallado](#detailed-error-schema)). `Reintentar`: Recomendación de reintento (`sí` para varios intentos, `una vez` para un solo reintento, `no` para errores graves). Los asteriscos (*) indican consideraciones especiales que se describen en la sección [Descripciones](#descriptions).

### Mensajes de error de Frame.io




| Mensaje | Tipo de error | Código HTTP | Esquema | Reintentar |
| ----------------------------- | ---------------------------------------------------------- | ------------------ | ----------------- | ------- |
| &quot;access_denied&quot; | [AccessDenied](#accessdenied) | 401 | [sencillo](#simple-error-schema) | una vez |
| &quot;authorization_pending&quot; | [AuthorizationPending](#authorizationpending) | 400 | [sencillo](#simple-error-schema) | sí |
| &quot;Channel Paused&quot; | [ChannelPaused](#channelpaused) | 409 | [sencillo](#simple-error-schema) | no |
| &quot;expired_token&quot; | [ExpiredToken](#expiredtoken) | 400 | [sencillo](#simple-error-schema) | no |
| &quot;Invalid Argument&quot; | [InvalidArgument](#invalidargument) | 422 | [detallado](#detailed-error-schema) | no |
| &quot;invalid_client&quot; | [InvalidClient](#invalidclient) | 400 | [sencillo](#simple-error-schema) | no |
| &quot;Invalid client version&quot; | [InvalidClientVersion](#invalidclientversion) | 400 | [sencillo](#simple-error-schema) | no |
| &quot;invalid_grant&quot; | [InvalidGrant](#invalidgrant) | 400 | [sencillo](#simple-error-schema) | no |
| &quot;invalid_request&quot; | [InvalidRequest](#invalidrequest) | 400 | [sencillo](#simple-error-schema) | una vez |
| &quot;Not Authorized&quot; | [UnauthorizedClient](#unauthorizedclient) | 401 | [detallado](#detailed-error-schema) | no |
| &quot;slow_down&quot; | [SlowDown](#slowdown) | 400 | [sencillo](#simple-error-schema) | sí |
| &quot;unauthorized_client&quot; | [UnauthorizedClient](#unauthorizedclient) | 401 | [sencillo](#simple-error-schema) | sí* |




### Códigos de estado de Frame.io




| Código HTTP | Tipo de error | Reintentar |
| --------------- | ------------------------------------------------------ | ------- |
| 400 | [InvalidRequest](#invalidrequest) | una vez |
| 401 | [UnauthorizedClient](#unauthorizedclient) | no |
| 422 | [InvalidContentType](#invalidcontenttype) | no |
| 429 | [SlowDown](#slowdown) | sí |
| 500 | [InternalServerError](#internalservererror) | sí |




### Errores de AWS

Consulte la [documentación de AWS](https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html#ErrorCodeList) para obtener descripciones detalladas.
| Error | Reintentar |
| ------------------------- | ------- |
| InternalError | sí |
| OperationAborted | sí |
| RequestTimeout | sí |
| ServiceUnavailable | sí |
| SlowDown | sí |
| [Todos los demás errores] | una vez |



<Info title="Analizar errores similares de AWS">
  Tanto `SlowDown` como `ServiceUnavailable` de AWS indican problemas con la velocidad de la solicitud y pueden abordarse de manera similar al error `SlowDown` de Frame.io, implementando una espera exponencial. De manera similar, `InternalError` de AWS corresponde conceptualmente a `InternalServerError` en nuestra API.
</Info>


### Descripciones





#### AccessDenied





Se devuelve cuando un usuario rechaza la autorización durante el emparejamiento del dispositivo.





#### AuthorizationPending

Indica que un usuario aún no ha introducido el código de emparejamiento del dispositivo. Continúe con el sondeo tras el periodo de `interval` especificado en la respuesta del código del dispositivo.

#### ChannelPaused





El canal del dispositivo estaba en pausa cuando se creó el activo. *No vuelva a intentar cargar este activo.*





#### ExpiredToken





El código de emparejamiento del dispositivo ha caducado. Genere un nuevo código y reinicie el proceso de emparejamiento.





#### InternalServerError

Indica un problema inesperado del backend. Vuelva a intentarlo una vez e informe de los errores `500` a nuestro equipo para que los investiguen. Tenga en cuenta que algunos problemas conocidos devuelven errores `500` cuando deberían devolver `InvalidRequest`:
* Intentar cargar en un canal de dispositivo que no exista
* Solicitar un recuento de fragmentos personalizado no válido




#### InvalidArgument





Un parámetro de carga útil contenía un valor no válido. Verifique que los valores de los parámetros coincidan con las expectativas de la API.





#### InvalidContentType

El encabezado `Content-Type` de la solicitud no es compatible. De manera general, la API acepta:
* `form/multipart` (solo puntos finales de autorización)
* `application/x-www-form-urlencoded` (todos los puntos finales)
* `application/json` (puntos finales que no son de autorización)




#### InvalidClient

Las credenciales proporcionadas (`client_id`, `client_secret`, etc.) no se han reconocido. Verifique las credenciales de su integración.

### InvalidClientVersion

El encabezado `x-client-version` estaba duplicado o contenía una [versión semántica](https://semver.org/) no válida.

#### InvalidGrant





El tipo de concesión de autorización no es válido. Revise las guías de autorización para consultar los valores correctos.





#### InvalidRequest





Los parámetros de la solicitud o el formato de carga útil son incorrectos. Verifique los nombres de los campos y los formatos de los valores.





Si se recibe durante la actualización del token, su token de actualización ha caducado y debe reiniciar el proceso de autorización.





#### SlowDown





Ha superado los límites de frecuencia de solicitud. Implemente una espera exponencial para las solicitudes posteriores. Tenga en cuenta que realizar varias solicitudes de código de dispositivo en la misma conexión TCP puede provocar este error: cree nuevas conexiones para cada solicitud de emparejamiento.





#### UnauthorizedClient

Normalmente indica que falta `access_token` o ha caducado. Si recibe este error, actualice su token antes de volver a intentarlo.

Si se produce durante la actualización del token, debe reiniciar el proceso de autorización e indicar al usuario que se vuelva a conectar.





Este error también puede producirse al acceder a recursos fuera del ámbito de autorización del dispositivo o cuando un proyecto ha deshabilitado los dispositivos de C2C. Verifique que haya solicitado los ámbitos adecuados durante la autorización.





*Si este error se produce durante la actualización del token, deberá reiniciarse todo el proceso de autorización con intervención del usuario.*





## Próximos pasos

Le recomendamos que se ponga en contacto con nuestro equipo si tiene alguna pregunta y a continuar con la [guía avanzada sobre las cargas](./how-to-advanced-uploads). Esperamos poder ayudarle con el progreso de su integración. Si aún no lo ha hecho, revise la guía [Implementar C2C: Configuración](./implementing-c2c-setting-up) antes de continuar. Necesitará el `access_token` que se obtiene durante el [proceso de autenticación y autorización](./implementing-c2c-authentication-and-authorization). Esta guía se basa en la [guía básica sobre las cargas](./how-to-basic-upload) y la [guía avanzada sobre las cargas](./how-to-advanced-uploads).