{"record":{"id":"66a4b0e4c2f76b46","repo":"clockworklabs/SpacetimeDB","slug":"failed-to-get-token","errorCode":null,"errorMessage":"Failed to get token: {}","messagePattern":"Failed to get token: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/cli/src/subcommands/login.rs","lineNumber":277,"sourceCode":"#[derive(Deserialize, Debug)]\nstruct SpacetimeDBTokenData {\n    token: String,\n}\n\nasync fn spacetimedb_login(remote: &Url, web_session_token: &String) -> Result<String, anyhow::Error> {\n    let client = reqwest::Client::new();\n\n    let response: SpacetimeDBTokenResponse = client\n        .post(remote.join(\"api/spacetimedb-token\")?)\n        .header(\"Authorization\", format!(\"Bearer {web_session_token}\"))\n        .send()\n        .await?\n        .error_for_status()?\n        .json()\n        .await?;\n\n    if !response.success {\n        return Err(anyhow::anyhow!(\n            \"Failed to get token: {}\",\n            response.error.unwrap_or(\"Unknown error\".to_string())\n        ));\n    }\n    Ok(response.data.unwrap().token.clone())\n}\n\n#[derive(Debug, Clone, Deserialize)]\nstruct LocalLoginResponse {\n    pub token: String,\n}\n\nasync fn spacetimedb_direct_login(host: &Url) -> Result<String, anyhow::Error> {\n    let client = reqwest::Client::new();\n    let response: LocalLoginResponse = client\n        .post(host.join(\"/v1/identity\")?)\n        .send()\n        .await?","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/crates/cli/src/subcommands/login.rs#L259-L295","documentation":"After browser approval, the CLI exchanges the web session token for a SpacetimeDB token via POST api/spacetimedb-token. A body-level success=false fails the exchange; the server's error string is included when present, else 'Unknown error' (login.rs:277).","triggerScenarios":"Completing browser approval, then the token-exchange step failing server-side — e.g. the session token expired, was invalidated by a server restart, or is unknown to the node handling the exchange.","commonSituations":"Waiting too long between browser approval and exchange; server restart or load balancing to a node without the session; CLI/server version skew; clock skew affecting token validity.","solutions":["Restart the login flow and complete the browser approval without pausing","Read the embedded server error string for the specific reason","Update CLI and server to matching versions and retry against a healthy node"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for i in 1 2; do\n  spacetime login && break   # complete browser approval immediately after it opens\n  echo \"token exchange failed, retrying\" >&2; sleep 2\ndone","preventionTips":["Finish the browser approval step without delay","Restart the login flow on exchange failure instead of retrying the browser step","Avoid login across server restarts or redeploys"],"tags":["login","auth","token-exchange","web-login"],"backgroundTag":"auth-token-exchange-failed","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}