OtterMind/Chat2DB · critical · RuntimeError
RELAY_TOKEN must contain at least 32 characters
Error message
RELAY_TOKEN must contain at least 32 characters
What it means
Raised by RelayConfig.from_environment (relay_server.py:60) as a RuntimeError when RELAY_TOKEN has fewer than 32 characters. The relay authenticates inbound requests by exact Bearer-token comparison, so a short token is treated as misconfiguration and the server refuses to start.
Source
Thrown at script/github/qq_relay/relay_server.py:60
@dataclass(frozen=True)
class RelayConfig:
relay_token: str
onebot_token: str
onebot_url: str
repository: str
group_id: int
max_message_length: int = 900
rate_limit: int = 30
rate_window_seconds: int = 60
@classmethod
def from_environment(cls) -> "RelayConfig":
relay_token = os.environ.get("RELAY_TOKEN", "")
onebot_token = os.environ.get("ONEBOT_TOKEN", "")
group_id = os.environ.get("QQ_GROUP_ID", "")
if len(relay_token) < 32:
raise RuntimeError("RELAY_TOKEN must contain at least 32 characters")
if len(onebot_token) < 32:
raise RuntimeError("ONEBOT_TOKEN must contain at least 32 characters")
if not group_id.isdigit():
raise RuntimeError("QQ_GROUP_ID must be a numeric QQ group number")
return cls(
relay_token=relay_token,
onebot_token=onebot_token,
onebot_url=os.environ.get("ONEBOT_URL", "http://napcat:3000"),
repository=os.environ.get("RELAY_REPOSITORY", "OtterMind/Chat2DB"),
group_id=int(group_id),
max_message_length=int(os.environ.get("RELAY_MAX_MESSAGE_LENGTH", "900")),
rate_limit=int(os.environ.get("RELAY_RATE_LIMIT", "30")),
)
class RateLimiter:
def __init__(self, limit: int, window_seconds: int):
self.limit = limitView on GitHub (pinned to 5ee1e990e7)
Solutions
- Generate a token of at least 32 characters, e.g. python -c "import secrets;print(secrets.token_urlsafe(48))".
- Set RELAY_TOKEN in the relay's environment (Compose env, systemd, or container env).
- Use the same value for QQ_RELAY_TOKEN in the GitHub Actions notifier.
Example fix
RELAY_TOKEN=$(python -c 'import secrets;print(secrets.token_urlsafe(48))')
Defensive patterns
Strategy: validation
Validate before calling
import os, secrets
token = os.environ.get("RELAY_TOKEN", "")
if len(token) < 32:
token = secrets.token_urlsafe(48)
print(f"RELAY_TOKEN too short; generated a new one (set it permanently): {token}") Type guard
def is_strong_token(value: str) -> bool:
return len(value) >= 32 Prevention
- Generate tokens with secrets.token_urlsafe(48).
- Mount RELAY_TOKEN as an env var in the relay deployment.
- Use the identical value for QQ_RELAY_TOKEN in the notifier.
When it happens
Trigger: Starting the relay server with RELAY_TOKEN unset, empty, or shorter than 32 chars. from_environment is called once at startup in main(), so this is fatal before the server binds.
Common situations: RELAY_TOKEN not set in the container/host environment; a short placeholder value used during setup; the secret truncated when copied; deploying without the env var mounted.
Related errors
- ONEBOT_TOKEN must contain at least 32 characters
- Missing required GitHub Actions secrets: {missing}
- QQ_GROUP_ID must be a numeric QQ group number
- Prepared QQ notification contains a OneBot CQ code
- QQ_RELAY_URL must be an HTTPS URL without credentials or a f
AI-assisted analysis of OtterMind/Chat2DB@5ee1e990e7 (2026-08-14).
Data as JSON: /api/errors/143f63b8f2e743d9.
Report an issue: GitHub.