usestrix/strix · error · RelayError
unavailable
unavailable
Error message
unavailable
What it means
RelayError('unavailable') raised by _post_json() in strix/interface/viewer/auth.py when the HTTP request to the Strix relay (app.strix.ai) raises requests.RequestException — connection refused, DNS failure, TLS error, or timeout. It is the generic network-level failure for all relay endpoints (/api/oss/otp/start, /otp/verify, /feedback, /report/send).
Source
Thrown at strix/interface/viewer/auth.py:154
def _post_json(path: str, payload: dict[str, Any], *, timeout: int) -> tuple[int, dict[str, Any]]:
"""POST JSON to the relay. Returns (status, parsed body).
Raises RelayError("unavailable") for network/transport failures. HTTP
error responses (4xx/5xx) are returned as (status, body) for the caller to
map, not raised.
"""
url = f"{_app_url()}{path}"
try:
with requests.post(
url,
json=payload,
headers={"Accept": "application/json"},
timeout=timeout,
) as response:
return response.status_code, _parse_body(response.content)
except requests.RequestException as exc:
logger.warning("relay request to %s failed: %s", path, exc)
raise RelayError("unavailable") from exc
def _parse_body(raw: bytes) -> dict[str, Any]:
try:
data = json.loads(raw or b"{}")
except json.JSONDecodeError:
return {}
return data if isinstance(data, dict) else {}
def otp_start(email: str) -> None:
"""Ask the relay to email a verification code. Raises RelayError on failure."""
status, data = _post_json("/api/oss/otp/start", {"email": email}, timeout=_OTP_TIMEOUT)
if status == 200:
return
if status == 429:
raise RelayError("rate_limited")
if status == 400:View on GitHub (pinned to 8551339130)
Solutions
- Check basic connectivity: curl -sS https://app.strix.ai/ -o /dev/null -w '%{http_code}'
- Configure proxy env vars if egress requires them: export HTTPS_PROXY=http://proxy.corp:8080
- Retry after a short delay — transient network/DNS failures commonly clear
- If behind TLS interception, ensure the corporate CA is in the trust store (REQUESTS_CA_BUNDLE=/path/to/ca.pem)
Defensive patterns
Strategy: retry
Validate before calling
import socket, urllib.request
def relay_reachable(url="https://app.strix.ai") -> bool:
try:
urllib.request.urlopen(url, timeout=5)
return True
except Exception:
return False Try / catch
from strix.interface.viewer.auth import RelayError
for attempt in range(3):
try:
otp_start(email)
break
except RelayError as e:
if e.code == "unavailable" and attempt < 2:
time.sleep(2 ** attempt)
continue
raise Prevention
- Verify egress to app.strix.ai before starting verification flows
- Set HTTPS_PROXY in proxied environments
- Treat 'unavailable' as retryable but cap retries with backoff
- Keep the relay URL configuration pristine
When it happens
Trigger: Any otp_start(), otp_verify(), feedback_submit(), or report_send() call while offline, behind a blocking proxy, with DNS resolution failure for the app URL, or when the relay endpoint returns an unmapped status code (the final 'raise RelayError("unavailable")' fallbacks). Also raised by otp_verify when a 200 response lacks a parseable expires_at (gate fails closed).
Common situations: Corporate egress proxy or firewall blocking app.strix.ai; airplane mode / flaky WiFi during OTP verification; relay temporarily down or returning 5xx; self-signed TLS interception appliance; typo in a custom app URL override.
Related errors
AI-assisted analysis of usestrix/strix@8551339130 (2026-08-15).
Data as JSON: /api/errors/db835d202cc7746d.
Report an issue: GitHub.