Error handling

Caching and quotas: Caching & monitoring.

Platform errors (401, 403, 422, 429, 5xx, retry/backoff, rate-limit headers): Error Handling.

Endpoint 404 samples: METAR · TAF · Winds Aloft.

When weather data is missing

Two distinct 404 cases - same HTTP status and JSON shape ({ "detail": "..." }), different meaning:

METAR 404. No weather observation station at this ICAO. Common for private strips, many military airfields, and some international airports that don't report to the ASOS/AWOS network. The airport may still exist - it just doesn't report METARs. Show Weather not available and let users proceed if appropriate.

TAF 404. The airport may have a METAR, but no TAF is issued. Smaller airports without significant instrument traffic often have METAR only. Fetch METAR normally, skip the TAF, and display current conditions only.

import requests

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


def get_weather(icao: str) -> dict:
    """
    Returns a dict with 'metar' and 'taf' keys.
    Either can be None if data is unavailable for this airport.
    """
    result = {"metar": None, "taf": None}

    r = requests.get(f"{BASE}/weather/metar/{icao}", headers=HEADERS, params={"parsed": "true"}, timeout=(10, 15))
    if r.status_code == 200:
        result["metar"] = r.json()
    elif r.status_code != 404:
        r.raise_for_status()

    r = requests.get(f"{BASE}/weather/taf/{icao}", headers=HEADERS, params={"parsed": "true"}, timeout=(10, 15))
    if r.status_code == 200:
        result["taf"] = r.json()
    elif r.status_code != 404:
        r.raise_for_status()

    return result


# weather = get_weather("KOXB")  # small airport, no TAF
# print("METAR:", "available" if weather["metar"] else "not available")
# print("TAF:",   "available" if weather["taf"]   else "not available")

Render available METAR/TAF data and label gaps explicitly (for example, "No forecast for this airport"). A weather 404 means the product is not published for that ICAO, not a client bug.

For transient failures (429, 5xx), use the retry helper on Error Handling.

En-route endpoints (bbox)

Winds Aloft, PIREPs, and AIRMET/SIGMET use a bbox query - not a single ICAO. Error semantics differ from METAR/TAF:

EndpointEmpty result404Notes
Winds Aloft-No FB stations in bboxUS coverage only - widen bbox or check coordinates
PIREPsreports: [], total: 0- (use 400 for bad bbox)No recent pilot reports - not an error
AIRMET/SIGMETreports: [], total: 0- (use 400 for bad bbox)No active advisories - common in VFR weather
import requests

HEADERS = {
    "X-RapidAPI-Key": "YOUR_RAPIDAPI_KEY",
    "X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"
BBOX = "39,-80,42,-73"  # example corridor


def enroute_weather(bbox: str) -> dict:
    """Fetch en-route layers. Empty lists are valid - do not treat as failures."""
    out = {"winds": None, "pireps": [], "airsigmets": []}

    r = requests.get(
        f"{BASE}/weather/winds-aloft",
        headers=HEADERS,
        params={"bbox": bbox, "forecast": 12, "level": "low"},
        timeout=(10, 20),
    )
    if r.status_code == 200:
        out["winds"] = r.json()
    elif r.status_code != 404:
        r.raise_for_status()

    r = requests.get(
        f"{BASE}/weather/pireps",
        headers=HEADERS,
        params={"bbox": bbox, "hours": 3},
        timeout=(10, 20),
    )
    r.raise_for_status()
    out["pireps"] = r.json().get("reports") or []

    r = requests.get(
        f"{BASE}/weather/airsigmet",
        headers=HEADERS,
        params={"bbox": bbox, "type": "airmet"},
        timeout=(10, 25),
    )
    r.raise_for_status()
    out["airsigmets"] = r.json().get("reports") or []

    return out


# wx = enroute_weather(BBOX)
# print("Winds stations:", wx["winds"]["total"] if wx["winds"] else "none in bbox")
# print("PIREPs:", len(wx["pireps"]))
# print("AIRMETs:", len(wx["airsigmets"]))

Show explicit empty states in the UI ("No pilot reports in the last 3 h", "No active AIRMETs") instead of error banners.


Related: METAR · TAF · Winds Aloft · PIREPs · AIRMET/SIGMET · Production patterns · Airport use cases · En-route use cases