usestrix/strix · warning · RelayError
invalid_code
invalid_code
Error message
invalid_code
What it means
RelayError('invalid_code') raised by otp_verify() when POST /api/oss/otp/verify returns 403 — the submitted OTP code does not match the one the relay emailed, or it has expired. This is the single 'wrong code' signal from the verification flow.
Source
Thrown at strix/interface/viewer/auth.py:196
raise RelayError("unavailable")
def otp_verify(email: str, code: str) -> dict[str, Any]:
"""Verify a code. Returns ``{token, email, expires_at}`` or raises RelayError."""
status, data = _post_json(
"/api/oss/otp/verify",
{"email": email, "code": code},
timeout=_OTP_TIMEOUT,
)
if status == 200 and isinstance(data.get("token"), str):
# A token with no usable expiry cannot unlock history locally (the gate
# fails closed), so treat such a response as a failed verification rather
# than reporting success and then leaving the user stuck unverified.
if parse_expiry(data.get("expires_at")) is None:
raise RelayError("unavailable")
return data
if status == 403:
raise RelayError("invalid_code")
raise RelayError("unavailable")
def feedback_submit(email: str, message: str) -> None:
"""Relay a feedback message + email to Strix. No verification is required;
the email is taken as given. Raises RelayError on failure."""
status, data = _post_json(
"/api/oss/feedback",
{"email": email, "message": message},
timeout=_OTP_TIMEOUT,
)
if status == 200:
return
if status == 429:
raise RelayError("rate_limited")
if status == 400:
code = data.get("error")
if code in ("invalid_email", "invalid_message"):View on GitHub (pinned to 8551339130)
Solutions
- Re-enter the code carefully, copying it verbatim from the newest email (watch for similar glyphs like 0/O, 1/l)
- If it may have expired, request a fresh code via otp_start() and use that one within its validity window
- Strip whitespace and normalize case before submitting: code.strip().upper() if codes are case-insensitive per relay format
- Guard against autofill/old codes: always use the most recent email, not a pinned one
Example fix
# before
otp_verify(email, input('code: ')) # pasted with trailing space -> invalid_code
# after
otp_verify(email, input('code: ').strip()) Defensive patterns
Strategy: try-catch
Validate before calling
import re
def plausible_code(code: str) -> bool:
c = code.strip()
return bool(re.fullmatch(r"[0-9A-Za-z]{4,10}", c)) Try / catch
try:
otp_verify(email, code)
except RelayError as e:
if e.code == "invalid_code":
code = prompt("wrong or expired code; re-enter or request a new one").strip()
otp_verify(email, code)
else:
raise Prevention
- Strip whitespace from hand-typed or pasted codes
- Offer a 'request new code' action after 2-3 failed attempts
- Use the newest email; disable autofill of old codes
When it happens
Trigger: Calling otp_verify(email, '000000') with a mistyped or transposed code; submitting after the code's validity window elapsed; re-submiting a code that was already consumed; case/whitespace corruption when the code is copied from the email or typed by hand.
Common situations: User typo entering the 6-digit code; code expired because the user waited too long before entering it; email client rendering the code with hidden characters; autofill inserting an old code from a previous verification.
Related errors
AI-assisted analysis of usestrix/strix@8551339130 (2026-08-15).
Data as JSON: /api/errors/fda5cd85a61b0a58.
Report an issue: GitHub.