# Обработка ошибок

Обработка ошибок ML-прогнозов в продакшне — неподдерживаемые маршруты, ошибки валидации и резервные сценарии.



Кэширование и мониторинг: [Кэширование и мониторинг](/docs/v31/ml-integration-production).

**Ошибки платформы** (401, 403, 422, 429, 5xx, повторные попытки и экспоненциальная задержка, заголовки ограничения частоты запросов): [Обработка ошибок](/docs/errors).

### Время полёта: 422 — нераспознанные коды аэропортов [#flight-time-422--unrecognised-airport-codes]

`GET /ml/flight-time` проверяет, что и `from`, и `to` соответствуют известным аэропортам. Неизвестный или некорректный код возвращает `422` с сообщением в detail, указывающим, какой код не прошёл проверку.

| Код   | Значение                            | Как исправить                                                                                                                                                      |
| ----- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `422` | `from` или `to` не распознан        | Используйте корректный код ICAO (4 буквы, например `KJFK`) или IATA (3 буквы, например `JFK`). Найти код можно через [Поиск аэропортов](/docs/v31/airport-search). |
| `404` | Нет данных о маршруте для этой пары | Модели не хватает исторических данных для этой пары городов. Покажите «Оценка недоступна».                                                                         |

**Примечание:** результат — это **статистическое среднее**, полученное из исторических эксплуатационных данных, а не прогноз в реальном времени. Ветер и текущие условия на маршруте не входят во входные данные модели. Сообщайте об этом, когда показываете оценки пассажирам или специалистам по планированию расписаний.

```python
import os
import requests

HEADERS = {
    "X-RapidAPI-Key": os.getenv("RAPIDAPI_KEY", "YOUR_RAPIDAPI_KEY"),
    "X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"


def fetch_flight_time(origin: str, destination: str, aircraft: str | None = None) -> dict | None:
    """
    Fetch ML flight time estimate. Returns None on 404 (no data for pair).
    Raises ValueError on 422 (invalid airport code).
    """
    params: dict[str, str] = {"from": origin, "to": destination}
    if aircraft:
        params["aircraft"] = aircraft
    r = requests.get(
        f"{BASE}/ml/flight-time",
        headers=HEADERS,
        params=params,
        timeout=(10, 15),
    )
    if r.status_code == 404:
        return None
    if r.status_code == 422:
        detail = r.json().get("detail", "invalid airport code")
        raise ValueError(f"422 Unprocessable: {detail}")
    r.raise_for_status()
    return r.json()


# Valid request — KJFK to KLAX
if __name__ == "__main__":
    data = fetch_flight_time("KJFK", "KLAX", aircraft="B738")
    if data:
        print(
            f"Estimated: {data['estimated_hours_display']}  "
            f"({data['min_minutes']}–{data['max_minutes']} min range)"
        )
        print("Statistical average — actual time varies with winds and routing.")
    else:
        print("No estimate available for this route.")

    try:
        fetch_flight_time("ZZZZ", "KLAX")
    except ValueError as exc:
        print(f"Caught expected error: {exc}")
```

### Выбросы углерода: 422 — отсутствуют обязательные параметры [#carbon-422--missing-required-parameters]

`GET /carbon/estimate` требует либо пару аэропортов (`departure_icao` + `arrival_icao`), **либо** `callsign`. Если не указано ни то, ни другое, возвращается `422`.

| Код   | Значение                                      | Как исправить                                                                                                                         |
| ----- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `422` | Не передана ни пара аэропортов, ни `callsign` | Укажите `departure_icao` + `arrival_icao` или `callsign`.                                                                             |
| `422` | Нераспознанный код аэропорта                  | Убедитесь, что ICAO-коды — корректные 4-буквенные идентификаторы. Найти код можно через [Поиск аэропортов](/docs/v31/airport-search). |
| `404` | Нет данных о выбросах для этой пары           | Маршрут не охвачен моделью. Покажите «Оценка недоступна».                                                                             |

**Раскрытие RFI:** передача `include_rfi=true` применяет к базовому значению CO₂ множитель [индекса радиационного воздействия](https://en.wikipedia.org/wiki/Radiative_forcing) (Radiative Forcing Index, \~2×). Если в ответе есть `rfi_applied: true`, укажите в интерфейсе, что отображаемое значение учитывает климатическое воздействие помимо одного лишь CO₂ (согласно рекомендациям [ICAO Doc 9988](https://www.icao.int/environmental-protection/CarbonOffset/Pages/default.aspx)).

```python
import os
import requests

HEADERS = {
    "X-RapidAPI-Key": os.getenv("RAPIDAPI_KEY", "YOUR_RAPIDAPI_KEY"),
    "X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"


def fetch_carbon(
    departure_icao: str | None = None,
    arrival_icao: str | None = None,
    callsign: str | None = None,
    passengers: int = 1,
    include_rfi: bool = False,
) -> dict | None:
    """
    Fetch carbon estimate. Requires departure_icao+arrival_icao or callsign.
    Returns None on 404. Raises ValueError on 422.
    """
    params: dict[str, str | int] = {
        "passengers": passengers,
        "include_rfi": str(include_rfi).lower(),
    }
    if departure_icao:
        params["departure_icao"] = departure_icao
    if arrival_icao:
        params["arrival_icao"] = arrival_icao
    if callsign:
        params["callsign"] = callsign

    r = requests.get(
        f"{BASE}/carbon/estimate",
        headers=HEADERS,
        params=params,
        timeout=(10, 15),
    )
    if r.status_code == 404:
        return None
    if r.status_code == 422:
        detail = r.json().get("detail", "validation error")
        raise ValueError(f"422 Unprocessable: {detail}")
    r.raise_for_status()
    return r.json()


# 1. Attempt without required params — expect 422
if __name__ == "__main__":
    try:
        fetch_carbon()
    except ValueError as exc:
        print(f"Missing params error: {exc}")

    data = fetch_carbon(departure_icao="KJFK", arrival_icao="KLAX", passengers=1)
    if data:
        co2 = data.get("co2_kg_per_passenger", 0.0)
        rfi = data.get("rfi_applied", False)
        print(f"CO₂/passenger: {co2:.1f} kg  (RFI applied: {rfi})")
        if rfi:
            print(
                "Disclosure: figure includes radiative forcing effects "
                "(~2× base CO₂, ICAO Doc 9988)."
            )
    else:
        print("No estimate available for this route.")
```

Для временных сбоев (`429`, `5xx`) используйте вспомогательную функцию повторных попыток из раздела [Обработка ошибок](/docs/errors#retry-rules).

***

См. также: [Время полёта](/docs/v31/flight-time) · [Выбросы CO₂](/docs/v31/carbon) · [Кэширование и мониторинг](/docs/v31/ml-integration-production) · [Обработка ошибок](/docs/errors)
