BigPizzaV3/CodexPlusPlus · error · anyhow::Error
token is required
Error message
token is required
What it means
parse_registration validates the first WebSocket message from a relay client; after successfully decoding a register envelope, it found registration.token empty or missing. Without a token the relay cannot authenticate or namespace the connection, so the handshake is rejected before any proxying happens.
Solutions
- Include the valid relay token in the registration message
- Regenerate/copy the token from the host and reconfigure the client
- Check that the token env var/config key is actually set and non-blank before connecting
Example fix
// before
{ "message_type": "register", "room": "r1", "token": "", "role": "client" }
// after
{ "message_type": "register", "room": "r1", "token": "<relay-token>", "role": "client" } Defensive patterns
Strategy: validation
Validate before calling
if (!token || !token.trim()) throw new Error('relay token is required before connecting'); Type guard
const hasToken = (t: string | undefined | null): t is string => typeof t === 'string' && t.trim().length > 0;
Try / catch
ws.onclose = (e) => { if (String(e.reason).includes('token is required')) promptForToken(); }; Prevention
- Copy the token from the host before client connect
- Fail fast client-side when the token env/config is unset
- Never send registration with blank token placeholders
When it happens
Trigger: First WebSocket registration frame (parse_registration, main.rs ~371) with token missing, "", or whitespace-only.
Common situations: Token not yet generated/copied from the host; env var or config holding the token is unset; token accidentally cleared when editing client settings.
Related errors
- room token mismatch
- first message must be registration json
- registration type must be register
- room is required
- API Key 不能为空
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19).
Data as JSON: /api/errors/fd219210ad95a90b.
Report an issue: GitHub.
Appendix: source
Thrown at apps/codex-plus-mobile-relay/src/main.rs:371
fn parse_registration(message: Message) -> anyhow::Result<Registration> {
let text = match message {
Message::Text(text) => text.to_string(),
Message::Binary(bytes) => {
String::from_utf8(bytes.to_vec()).context("binary registration must be utf-8 json")?
}
_ => bail!("first message must be registration json"),
};
let registration: RegisterMessage =
serde_json::from_str(&text).context("registration is not valid json")?;
if registration.message_type != "register" {
bail!("registration type must be register");
}
if registration.room.trim().is_empty() {
bail!("room is required");
}
if registration.token.trim().is_empty() {
bail!("token is required");
}
let role = Role::from_str(®istration.role).context("role must be host or client")?;
Ok(Registration {
role,
room: registration.room,
token: registration.token,
})
}
fn registration_from_uri(path: &str, query: Option<&str>) -> Option<Registration> {
let query = query?;
let role = match path {
"/host" => Some(Role::Host),
"/client" => Some(Role::Client),
"/ws" => query_value(query, "role").and_then(|role| Role::from_str(&role)),
_ => None,
}?;
let room = query_value(query, "room")?;View on GitHub (pinned to b1ed92e5e4)