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

  1. Re-authenticate in the agy/Antigravity client so a non-empty token is written, then re-import.
  2. Pre-check the token value before import: parse the JSON yourself and require a non-blank `access_token`/`accessToken`/`token`.
  3. 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

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


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/7f896b7227c5bb1e. Report an issue: GitHub.