tinyhumansai/openhuman · error

Smithery returned HTTP {status}: {}

Error message

Smithery returned HTTP {status}: {}

What it means

Raised by the Smithery MCP-catalog client when a paginated search against the Smithery registry returns any non-2xx HTTP status. The request itself completed (auth headers were already attached by apply_auth), so the status is Smithery's — or an intermediary proxy's — answer, not a transport failure. The message embeds the status code plus the first 200 bytes of the response body so the upstream API's own error text is visible; a warn! with the cache key is also emitted.

Source

Thrown at src/openhuman/mcp/registry/registries/smithery.rs:77

        let mut req = client.get(format!("{SMITHERY_BASE}/servers"));
        if !q.is_empty() {
            req = req.query(&[("q", q)]);
        }
        req = req
            .query(&[
                ("page", &page.to_string()),
                ("pageSize", &page_size.to_string()),
            ])
            .header("Accept", "application/json");
        req = apply_auth(config, req);

        let resp = req.send().await.context("Smithery search request failed")?;
        let status = resp.status();
        let body = resp.text().await.context("Smithery search read failed")?;

        if !status.is_success() {
            tracing::warn!("[smithery] search HTTP {status} for key={cache_key}");
            anyhow::bail!(
                "Smithery returned HTTP {status}: {}",
                &body[..body.len().min(200)]
            );
        }

        let parsed: SmitheryListResponse = serde_json::from_str(&body)
            .with_context(|| format!("Failed to parse Smithery list response: {body}"))?;

        let total_pages = parsed.pagination.total_pages;
        let servers = tag_source(parsed.servers);

        let _ = store::set_cached(config, &cache_key, &body);
        tracing::debug!(
            "[smithery] search ok servers={} total_pages={}",
            servers.len(),
            total_pages
        );

View on GitHub (pinned to 7491200858)

Solutions

  1. Reproduce outside the app: curl -i 'https://registry.smithery.ai/servers?q=<query>' and read the status and body.
  2. For 401/403, fix or remove the Smithery credentials that apply_auth attaches (the config-managed API key), then retry.
  3. For 429/5xx, wait a few seconds and retry — these are transient, and previously cached pages (store::set_cached) still serve the UI.
  4. For proxy interference (407/502 from a middlebox), allowlist registry.smithery.ai or bypass the proxy.

Example fix

// before
let page = registry.search(config, &query, page, page_size).await?;

// after — retry transient statuses once, fail fast on auth errors
let page = match registry.search(config, &query, page, page_size).await {
    Ok(p) => p,
    Err(e) if e.to_string().contains("HTTP 429") || e.to_string().contains("HTTP 5") => {
        tokio::time::sleep(std::time::Duration::from_secs(3)).await;
        registry.search(config, &query, page, page_size).await?
    }
    Err(e) => return Err(e),
};
Defensive patterns

Strategy: retry

Validate before calling

// Preflight: can we reach the Smithery registry at all?
async fn smithery_reachable(client: &reqwest::Client) -> bool {
    const BASE: &str = "https://registry.smithery.ai"; // same host the registry client uses
    match client.head(BASE).send().await {
        Ok(resp) => !resp.status().is_server_error(),
        Err(_) => false,
    }
}

Try / catch

Inspect the embedded status in err.to_string(): treat `HTTP 401`/`HTTP 403` as a credentials bug (do not retry), `HTTP 429`/`HTTP 5xx` as transient (retry with seconds-scale backoff), anything else as network/proxy. Log the 200-byte body prefix — it carries Smithery's own message.

Prevention

When it happens

Trigger: Calling the registry search flow (SmitheryRegistry::search with query/page/pageSize, the query params visible in the source) when Smithery answers 401/403 (invalid or missing API key attached by apply_auth), 429 (catalog rate limit during bulk or scripted installs), 5xx (registry outage), or when a corporate TLS-inspection proxy answers 407/502 for registry.smithery.ai.

Common situations: Expired or wrong Smithery API key in config; install scripts looping over catalog pages until rate-limited; VPN/proxy environments; Smithery API host or schema change after a registry update; a fully offline machine requesting a cache key that store::set_cached never populated.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/754a1ece39c3d6c4. Report an issue: GitHub.