Hmbown/CodeWhale · error · anyhow::Error
agy OAuth token member `{member}` is empty
Error message
agy OAuth token member `{member}` is empty What it means
After extracting the raw token value from the agy store, parse_agy_oauth_token_value finds it is JSON, locates one of the accepted members (`access_token`, `accessToken`, `token`), but that member is an empty or whitespace-only string. An empty token can never authenticate, so the parser bails instead of returning a value that would fail later with a confusing 401.
Source
Thrown at crates/tui/src/agy_credentials.rs:219
/// The stored value is opaque to Codewhale. Accept only shapes observed in
/// the official store — a bare token string or a JSON object with a token
/// member — and never synthesize or trim secrets beyond whitespace.
pub(crate) fn parse_agy_oauth_token_value(value: Option<String>) -> Result<Option<String>> {
let Some(raw) = value else {
return Ok(None);
};
let trimmed = raw.trim();
if trimmed.is_empty() {
return Ok(None);
}
if trimmed.starts_with('{') {
let parsed: serde_json::Value = serde_json::from_str(trimmed)
.with_context(|| "agy OAuth token value is malformed JSON")?;
for member in ["access_token", "accessToken", "token"] {
if let Some(token) = parsed.get(member).and_then(|v| v.as_str()) {
if token.trim().is_empty() {
bail!("agy OAuth token member `{member}` is empty");
}
return Ok(Some(token.to_string()));
}
}
bail!("agy OAuth token JSON carries no access token member");
}
Ok(Some(trimmed.to_string()))
}
#[cfg(test)]
mod tests {
use super::*;
use codewhale_config::ExternalCredentialReadGrant;
use std::collections::HashMap;
fn grant_for(path: &Path) -> ExternalCredentialReadGrant {
codewhale_config::ExternalCredentialConsentToml::read_only(
codewhale_config::ProviderKind::Antigravity,View on GitHub (pinned to 0c42157ee5)
Solutions
- Re-authenticate in the agy/Antigravity client so a non-empty token is written, then re-import.
- Pre-check the token value before import: parse the JSON yourself and require a non-blank `access_token`/`accessToken`/`token`.
- Treat as 'no credentials' in the UX: prompt for login rather than showing a parse error.
Example fix
// before
let token = antigravity_oauth_token_from_grant(&grant)?; // bails: member is empty
// after
let token = match antigravity_oauth_token_from_grant(&grant) {
Ok(t) => t,
Err(e) if e.to_string().contains("is empty") => {
return Ok(None); // treat as signed-out; prompt for login
}
Err(e) => return Err(e),
}; Defensive patterns
Strategy: fallback
Validate before calling
let raw = peek_token_value(grant.path())?; // read-only helper you control
if let Some(v) = raw.as_deref() {
if let Ok(json) = serde_json::from_str::<serde_json::Value>(v.trim()) {
for member in ["access_token", "accessToken", "token"] {
if let Some(t) = json.get(member).and_then(|x| x.as_str()) {
if t.trim().is_empty() { /* signed out; prompt login */ }
}
}
}
} Type guard
fn has_nonempty_token_member(v: &serde_json::Value) -> bool {
["access_token", "accessToken", "token"]
.iter()
.any(|m| v.get(*m).and_then(|x| x.as_str()).is_some_and(|s| !s.trim().is_empty()))
} Try / catch
match antigravity_oauth_token_from_grant(&grant) {
Ok(t) => t,
Err(e) if e.to_string().contains("is empty") => { /* treat as signed out; start login flow */ None }
Err(e) => return Err(e),
} Prevention
- Verify the agy client shows a signed-in session before importing.
- Map 'empty token member' errors to a sign-in prompt, not a generic parse failure.
- Re-import after re-authenticating; do not cache blanked tokens.
When it happens
Trigger: The state.vscdb token row holds JSON like `{"access_token":""}` or `{"accessToken":" "}` — typically a revoked, cleared, or half-written session from the agy client.
Common situations: User signed out of Antigravity but the row remains with blanked fields; a token refresh wrote an empty value before dying; a partially-synced profile.
Related errors
- agy OAuth token JSON carries no access token member
- invalid Codewhale-owned xAI OAuth generation; expected xai-a
- Codewhale-owned xAI OAuth file {} exceeds the {} byte limit
- Antigravity import requires an agy_cli grant, not {}
- external agy credential file {} is not a SQLite database
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/7f896b7227c5bb1e.
Report an issue: GitHub.