MetaCubeX/mihomo · error · HttpRequestError

[{status}] {reason}

Error message

[{status}] {reason}

What it means

HttpRequestError(status, reason) is raised at mihomo/client.py:95 for any status code other than 200/400/404, formatting the message as '[{status}] {reason}' (mihomo/errors.py:26). It is the catch-all transport/server-error channel of MihomoAPI.request: rate limiting, upstream outages, gateway errors, and anything unexpected all land here. The status attribute (exc.status) lets you branch on the exact code.

Source

Thrown at mihomo/client.py:95

            async with session.get(url, params=params) as response:
                match response.status:
                    case 200:
                        return await response.json(encoding="utf-8")
                    case 400:
                        try:
                            data = await response.json(encoding="utf-8")
                        except:
                            raise InvalidParams()
                        else:
                            if isinstance(data, dict) and (
                                detail := data.get("detail")
                            ):
                                raise InvalidParams(detail)
                            raise InvalidParams()
                    case 404:
                        raise UserNotFound()
                    case _:
                        raise HttpRequestError(response.status, str(response.reason))

    async def fetch_user(
        self,
        uid: int,
        *,
        replace_icon_name_with_url: bool = False,
    ) -> StarrailInfoParsed:
        """
        Fetches user data from the API.

        Args:
            - uid (`int`): The user ID.
            - replace_icon_name_with_url (`bool`): Whether to replace icon names with asset URLs.

        Returns:
            StarrailInfoParsed: The parsed user data from mihomo API.

        """

View on GitHub (pinned to 008b91bfe8)

Solutions

  1. Check exc.status: 429 → slow down and add exponential backoff; 5xx → the upstream is down, retry later; 403 → network/IP issue, not your code.
  2. Add a retry-with-jitter wrapper around fetch_user for transient 502/503/504, with a cap of 2–3 attempts.
  3. Respect a minimum interval between requests (e.g. ≥1s per UID) to stay under the rate limit.
  4. If sustained, verify https://api.mihomo.me health in a browser/curl and look for announced maintenance.

Example fix

// before
data = await client.fetch_user(uid)  # HttpRequestError [429] Too Many Requests kills the job

// after
import asyncio
for attempt in range(3):
    try:
        data = await client.fetch_user(uid)
        break
    except HttpRequestError as e:
        if e.status != 429 or attempt == 2:
            raise
        await asyncio.sleep(2 ** attempt)
Defensive patterns

Strategy: retry

Validate before calling

# Nothing to validate client-side — this is a server/network condition.
# Guard with a rate limiter before calling:
import asyncio
_lock = asyncio.Semaphore(1)  # serialize + space out requests
async def safe_fetch(client, uid):
    async with _lock:
        return await client.fetch_user(uid)

Type guard

def is_retryable_http_error(exc: HttpRequestError) -> bool:
    return exc.status in {429, 502, 503, 504}

Try / catch

from mihomo.errors import HttpRequestError

async def fetch_with_retry(client, uid, attempts=3):
    for i in range(attempts):
        try:
            return await client.fetch_user(uid)
        except HttpRequestError as e:
            if e.status not in {429, 502, 503, 504} or i == attempts - 1:
                raise
            await asyncio.sleep((2 ** i) + random.random())

Prevention

When it happens

Trigger: HTTP 429 from api.mihomo.me when you exceed the rate limit; 5xx (502/503/504) during upstream maintenance or Cloudflare incidents; 403 when the source IP is blocked; any other non-2xx code not specifically mapped in the match statement.

Common situations: Bots polling fetch_user in a tight loop without backoff and hitting 429; running scrapers from datacenter IPs that Cloudflare challenges with 403/503; the free mihomo API being down or under load (check its status/Discord); aiohttp behind corporate proxies returning unusual status codes.

Related errors


AI-assisted analysis of MetaCubeX/mihomo@008b91bfe8 (2026-08-27). Data as JSON: /api/errors/e3da956d1f91a035. Report an issue: GitHub.