> This page is for Da videocamera a cloud.

> 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.

# Guida pratica: Gestire gli errori

## Introduzione





Questa guida illustra la gestione degli errori durante l'interazione con l'API C2C. La gestione corretta degli errori HTTP è essenziale per un'integrazione solida con qualsiasi servizio di terze parti.





## Tipi di errori





Gli errori nell'integrazione possono avere varie origini, che si possono suddividere in quattro gruppi principali:




* **Errori I/O:** sono causati da operazioni hardware sul dispositivo, come operazioni di lettura/scrittura non riuscite
* **Errori dell'applicazione:** derivano da problemi nel codice dell'applicazione
* **Errori di rete:** si verificano nello stack di rete e vengono comunicati dalla libreria di rete
* **Errori API:** vengono generati dai servizi backend di Frame.io




Ogni categoria di errore richiede valutazioni specifiche per la gestione. Questa guida si concentra principalmente sugli errori API, anche se affronteremo le strategie generali per le altre categorie.





## Come vengono restituiti gli errori API





L'API Frame.io comunica gli errori attraverso due meccanismi principali:




* **Codici di stato:** codici di errore HTTP che indicano la natura del problema
* **Messaggi di errore:** contenuto del payload che fornisce dettagli aggiuntivi sull'errore, specialmente quando più condizioni di errore condividono lo stesso codice di stato




### Codici di stato degli errori

I codici di stato HTTP sono risposte numeriche standardizzate che comunicano l'esito di una richiesta HTTP. Per ulteriori informazioni, consulta [la documentazione dei codici di stato HTTP di Mozilla](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) o [HTTP Cats](https://http.cat/) per un approccio più visivo. Ogni endpoint dell'API Frame.io specifica un codice di stato di successo previsto, in genere `200 (OK)`, `201 (Created)` o `204 (No Content)`. Puoi verificare la riuscita dell'operazione controllando questi codici specifici o confermando che il codice rientri nell'intervallo 200-299. I codici di stato superiori a 399 indicano degli errori. La maggior parte degli errori API restituisce codici 4XX (400-499), che indicano problemi lato client. Gli errori fuori da questo intervallo derivano solitamente dall'infrastruttura di rete tra il dispositivo e il nostro servizio, con un'eccezione particolare per il codice `500 (Internal Server Error)`, che indica un problema imprevisto all'interno del nostro server. Analogamente, una risposta `404 (Not Found)` potrebbe essere generata da servizi intermedi invece che dal nostro backend, nonostante sia un codice 4XX.

Se riscontri codici di stato imprevisti, avvisa il nostro team.





### Schemi dei payload di errore





Frame.io restituisce dettagli degli errori in due formati: *semplice* e *dettagliato*. La logica di gestione degli errori deve supportare entrambi i formati.





### Schema di errore semplice

Ecco un esempio di richiesta non riuscita con un `client_secret` non corretto:

```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'
```





Risposta:





```text
HTTP/2 400
...

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





Lo schema semplice contiene solo un singolo campo per l'identificazione dell'errore.





### Schema di errore dettagliato





Per fare un confronto, ecco una richiesta senza autorizzazione adeguata:





```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
```





Risposta:





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

Gli errori dettagliati contengono un campo `message` che identifica il tipo di errore.

### Come determinare il tipo di errore





Quando vanno gestiti gli errori di Frame.io, controlla prima la presenza di un payload di errore e poi passa al codice di stato HTTP se non è presente alcun payload.





Ecco un'implementazione di base per la gestione degli errori:





**`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)
```





Le tabelle di ricerca degli errori a cui si fa riferimento in questo esempio sono fornite alla fine di questa guida.





### Errori AWS

Durante il caricamento dei chunk di file, interagisci direttamente con AWS S3, che ha il proprio formato di errore. Consulta [la documentazione degli errori comuni di AWS](https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html#ErrorCodeList) per i dettagli. Come regola generale, gli errori AWS non irreversibili devono essere ritentati almeno una volta.

Gli errori AWS vengono restituiti come 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>
```

L'elemento `Code` identifica il tipo di errore.

## Nuovi tentativi per gli errori





### Quando riprovare

Le tabelle degli errori in questa guida indicano quali errori API dovrebbero essere ritentati. Per errori non legati all'API r provenienti da operazioni I/O, librerie di rete o AWS, conviene riprovare quelli che potrebbero derivare da condizioni transitorie. La congestione di rete, le interruzioni temporanee del server o la perdita di pacchetti di solito giustificano nuovi tentativi. La maggior parte delle librerie di rete genera un errore di tipo `TimeoutError` quando una richiesta impiega troppo tempo, il che rappresenta un candidato ideale per un nuovo tentativo.

### Nel dubbio, riprova una volta

Gli ambienti di calcolo possono avere problemi imprevedibili. Anche nel caso di errori che appaiono irreversibili, spesso vale la pena fare un nuovo tentativo. Stati temporanei del sistema, anomalie hardware (come [alterazioni di bit causate da raggi cosmici](https://www.youtube.com/watch?v=AaZ_RSt0KP8)) o condizioni rare della memoria possono causare errori apparentemente fatali che si risolvono al secondo tentativo. Tuttavia, non bisogna eseguire nuovi tentativi per alcuni errori. Ad esempio, una risposta `409: CHANNEL PAUSED` durante la creazione di una risorsa indica che il dispositivo è in pausa e non dovrebbe eseguire caricamenti. Questo stato è deliberato ed è improbabile che cambi con un nuovo tentativo.

### Backoff esponenziale

Frame.io implementa limiti di frequenza che, se vengono superati, producono un errore `429: Slow Down` o uno stato `400` con questo payload:

```text
HTTP/2 400

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





Quando ricevi queste risposte, implementa il backoff esponenziale per i nuovi tentativi. Una formula consigliata per calcolare il ritardo (in secondi) è:





**`Python`**

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

Dove `attempt` inizia da 0. Questo produce ritardi di 0,5 s, 1 s, 2 s, 4 s, 8s, 16 s e 32 s. Tutti i tentativi successivi vengono effettuati dopo 32 secondi.
<Info title="Jitter del backoff">
  Consigliamo di aggiungere casualità (jitter) alla temporizzazione del backoff per prevenire la sincronizzazione delle richieste tra più dispositivi che si riprendono dalla stessa condizione di errore. Questo aiuta a mitigare il [problema del &quot;thundering herd&quot;](https://medium.com/@venkteshsubramaniam/the-thundering-herd-distributed-systems-rate-limiting-9128d20e1f00), ovvero quando vengono eseguiti nuovi tentativi per molti dispositivi contemporaneamente dopo un'interruzione. Un buon approccio è aggiungere uno scostamento casuale tra 0 e la metà del ritardo calcolato: `math.rand(0, delay // 2)`.
</Info>


Il backoff esponenziale è essenziale per gli errori causati dai limiti di frequenza, ma è anche utile per gestire in generale i problemi di rete e I/O. Questo approccio consente la risoluzione di vincoli temporanei delle risorse senza un ulteriore carico dovuto ai nuovi tentativi.





### Rilevamento dello stato di disconnessione





In caso di errori di rete, è possibile che Frame.io non sia raggiungibile per vari motivi:




* La rete locale non funziona
* I servizi di Frame.io stanno avendo dei problemi
* Un componente di rete intermedio non funziona




È importante rilevare queste condizioni. Quando un errore indica problemi di connettività, occorre implementare un'attività di monitoraggio che verifichi il ripristino del servizio e informi l'utente della disconnessione.





### Attesa della connessione e dell'autorizzazione





Progetta l'applicazione in modo da evitare richieste non necessarie quando il dispositivo sta aggiornando l'autorizzazione, è in attesa dell'autorizzazione utente o non può raggiungere Frame.io. Ciò riduce il carico di rete e migliora l'esperienza utente.

Blocca tutte le chiamate API (tranne quelle a `https://api.frame.io/health`) quando rilevi uno stato di disconnessione. Quando si verificano problemi di connettività, avvia un'attività in background che effettua il polling dell'endpoint di stato e blocca ulteriori chiamate API finché la connettività non viene ripristinata.

Allo stesso modo, se il token scade, blocca le chiamate dipendenti dall'autorizzazione finché non viene rilasciato un nuovo token. Se l'aggiornamento del token non riesce, avvisa l'utente di eseguire nuovamente l'autenticazione.





Durante il polling per rilevare lo stato della connessione, applica lo stesso approccio di backoff esponenziale descritto in precedenza.





### Timeout delle richieste





Configura valori di timeout appropriati per diversi tipi di richieste:




* **Predefinito**: 15 secondi per le richieste di base
* **Aggiornamento dell'autorizzazione**: 2 minuti per tenere conto di potenziali elaborazioni backend
* **Caricamento dei chunk di file**: 5 minuti per adattarsi a reti lente durante il trasferimento di dati più grandi




### Esempio di gestore di nuovi tentativi





Ecco un'implementazione in pseudocodice che mostra la gestione degli errori con backoff esponenziale:





**`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
```





## Tabelle degli errori





Le seguenti tabelle categorizzano gli errori dell'API Frame.io e forniscono indicazioni su come gestirli. Ecco cosa rappresenta ogni colonna:

`Messaggio`: l'identificatore del messaggio del payload dell'errore `Codice HTTP`: il codice di stato HTTP `Tipo di errore`: una categoria di errore concettuale (dettagliata nella sezione [descriptions](#descriptions)) `Schema`: il formato del payload dell'errore ([semplice](#simple-error-schema) o [dettagliato](#detailed-error-schema)) `Nuovo tentativo`: consiglio per un nuovo tentativo (`sì` per tentativi multipli, `una volta` per un singolo tentativo, `no` per errori irreversibili) Gli asterischi (*) indicano valutazioni speciali dettagliate nella sezione [Descrizioni](#descriptions).

### Messaggi di errore di Frame.io




| Messaggio | Tipo di errore | Codice HTTP | Schema | Nuovo tentativo |
| ----------------------------- | ---------------------------------------------------------- | ------------------ | ----------------- | ------- |
| &quot;access_denied&quot; | [AccessDenied](#accessdenied) | 401 | [semplice](#simple-error-schema) | una volta |
| &quot;authorization_pending&quot; | [AuthorizationPending](#authorizationpending) | 400 | [semplice](#simple-error-schema) | sì |
| &quot;Channel Paused&quot; | [ChannelPaused](#channelpaused) | 409 | [semplice](#simple-error-schema) | no |
| &quot;expired_token&quot; | [ExpiredToken](#expiredtoken) | 400 | [semplice](#simple-error-schema) | no |
| &quot;Invalid Argument&quot; | [InvalidArgument](#invalidargument) | 422 | [dettagliato](#detailed-error-schema) | no |
| &quot;invalid_client&quot; | [InvalidClient](#invalidclient) | 400 | [semplice](#simple-error-schema) | no |
| &quot;Invalid client version&quot; | [InvalidClientVersion](#invalidclientversion) | 400 | [semplice](#simple-error-schema) | no |
| &quot;invalid_grant&quot; | [InvalidGrant](#invalidgrant) | 400 | [semplice](#simple-error-schema) | no |
| &quot;invalid_request&quot; | [InvalidRequest](#invalidrequest) | 400 | [semplice](#simple-error-schema) | una volta |
| &quot;Not Authorized&quot; | [UnauthorizedClient](#unauthorizedclient) | 401 | [dettagliato](#detailed-error-schema) | no |
| &quot;slow_down&quot; | [SlowDown](#slowdown) | 400 | [semplice](#simple-error-schema) | sì |
| &quot;unauthorized_client&quot; | [UnauthorizedClient](#unauthorizedclient) | 401 | [semplice](#simple-error-schema) | yes* |




### Codici di stato di Frame.io




| Codice HTTP | Tipo di errore | Nuovo tentativo |
| --------------- | ------------------------------------------------------ | ------- |
| 400 | [InvalidRequest](#invalidrequest) | una volta |
| 401 | [UnauthorizedClient](#unauthorizedclient) | no |
| 422 | [InvalidContentType](#invalidcontenttype) | no |
| 429 | [SlowDown](#slowdown) | sì |
| 500 | [InternalServerError](#internalservererror) | sì |




### Errori AWS

[Consulta la documentazione di AWS](https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html#ErrorCodeList) per descrizioni dettagliate.
| Errore | Nuovo tentativo |
| ------------------------- | ------- |
| InternalError | sì |
| OperationAborted | sì |
| RequestTimeout | sì |
| ServiceUnavailable | sì |
| SlowDown | sì |
| [Tutti gli altri errori] | una volta |



<Info title="Analisi di errori AWS simili">
  Sia `SlowDown` che `ServiceUnavailable` di AWS indicano problemi di frequenza delle richieste e possono essere trattati in modo simile all'errore `SlowDown` di Frame.io, implementando il backoff esponenziale. Allo stesso modo, `InternalError` di AWS corrisponde concettualmente a `InternalServerError` nella nostra API.
</Info>


### Descrizioni





#### AccessDenied





Restituito quando un utente rifiuta l'autorizzazione durante l'associazione dispositivo.





#### AuthorizationPending

Indica che l'utente non ha ancora inserito il codice di associazione dispositivo. Continua il polling dopo il periodo (`interval`) specificato nella risposta del codice dispositivo.

#### ChannelPaused





Il canale del dispositivo era in pausa quando è stata creata la risorsa. *Non tentare di caricare nuovamente questa risorsa.*





#### ExpiredToken





Il codice di associazione del dispositivo è scaduto. Genera un nuovo codice e riavvia il processo di associazione.





#### InternalServerError

Indica un problema imprevisto del backend. Riprova una volta e segnala gli errori `500` al nostro team al fine di indagarli. Tieni presente che alcuni problemi noti restituiscono errori `500` quando dovrebbero invece restituire `InvalidRequest`:
* Tentativo di caricamento su un canale del dispositivo inesistente
* Richiesta non valida di un numero di chunk personalizzato




#### InvalidArgument





Un parametro del payload conteneva un valore non valido. Verifica che i valori dei parametri corrispondano alle aspettative dell'API.





#### InvalidContentType

L'intestazione `Content-Type` della richiesta non è supportata. L'API accetta generalmente:
* `form/multipart` (solo endpoint di autorizzazione)
* `application/x-www-form-urlencoded` (tutti gli endpoint)
* `application/json` (endpoint non di autorizzazione)




#### InvalidClient

Le credenziali fornite (`client_id`, `client_secret` ecc.) non sono state riconosciute. Verifica le credenziali di integrazione.

### InvalidClientVersion

L'intestazione `x-client-version` era duplicata o contiene una [versione semantica](https://semver.org/) non valida.

#### InvalidGrant





Il tipo di concessione delle autorizzazioni non è valido. Rivedi i valori corretti nelle guide di autorizzazione.





#### InvalidRequest





I parametri della richiesta o il formato del payload non sono corretti. Verifica i nomi dei campi e i formati dei valori.





Se l'errore compare durante l'aggiornamento del token, il token di aggiornamento è scaduto e occorre riavviare il processo di autorizzazione.





#### SlowDown





Hai superato i limiti di frequenza delle richieste. Implementa il backoff esponenziale per le richieste successive. Tieni presente che l'esecuzione di più richieste di codice del dispositivo sulla stessa connessione TCP può attivare questo errore. Crea nuove connessioni per ogni richiesta di abbinamento.





#### UnauthorizedClient

Indica in genere che l'`access_token` è scaduto o manca. Se ricevi questo errore, aggiorna il token prima di riprovare.

Se si verifica durante l'aggiornamento del token, devi riavviare il processo di autorizzazione e richiedere all'utente di riconnettersi.





Questo errore può anche verificarsi quando si accede a risorse al di fuori dell'ambito di autorizzazione del dispositivo o quando un progetto ha disabilitato i dispositivi C2C. Verifica di aver richiesto gli ambiti appropriati durante l'autorizzazione.





*Se questo errore si verifica durante l'aggiornamento del token, l'intero processo di autorizzazione deve essere riavviato con l'intervento dell'utente.*





## Passaggi successivi

Ti incoraggiamo a contattare il nostro team per qualsiasi domanda, poi vai alla [guida sui caricamenti avanzati](./how-to-advanced-uploads). Saremo lieti di aiutarti nel tuo percorso di implementazione. Se non l'hai già fatto, consulta la guida [Implementazione C2C: configurazione](./implementing-c2c-setting-up) prima di procedere. Avrai bisogno dell'`access_token` ottenuto durante il [processo di autenticazione e autorizzazione](./implementing-c2c-authentication-and-authorization). Questa guida si basa su [quella dedicata ai caricamenti di base](./how-to-basic-upload) e sulla [guida sui caricamenti avanzati](./how-to-advanced-uploads).