zeroclaw-labs/zeroclaw · error

Pending {} login is missing code verifier

Error message

Pending {} login is missing code verifier

What it means

load_pending_oauth_login reconstructs a PendingOAuthLogin from the persisted auth-<provider>-pending.json file. The PKCE code_verifier is mandatory to finish the OAuth exchange; it is read either from encrypted_code_verifier (decrypted via the secret store) or the legacy plaintext code_verifier field. If the file has neither field, resuming the login is impossible, so it bails with the provider name in the message.

Source

Thrown at crates/zeroclaw-providers/src/auth/mod.rs:985

    config: &Config,
    model_provider: &str,
) -> Result<Option<PendingOAuthLogin>> {
    let path = pending_oauth_login_path(config, model_provider);
    if !path.exists() {
        return Ok(None);
    }
    let bytes = std::fs::read(&path)?;
    if bytes.is_empty() {
        return Ok(None);
    }
    let persisted: PendingOAuthLoginFile = serde_json::from_slice(&bytes)?;
    let secret_store = pending_oauth_secret_store(config);
    let code_verifier = if let Some(encrypted) = persisted.encrypted_code_verifier {
        secret_store.decrypt(&encrypted)?
    } else if let Some(plaintext) = persisted.code_verifier {
        plaintext
    } else {
        anyhow::bail!("Pending {} login is missing code verifier", model_provider);
    };
    Ok(Some(PendingOAuthLogin {
        model_provider: persisted
            .model_provider
            .unwrap_or_else(|| model_provider.to_string()),
        profile: persisted.profile,
        code_verifier,
        state: persisted.state,
        created_at: persisted.created_at,
    }))
}

pub fn clear_pending_oauth_login(config: &Config, model_provider: &str) {
    let path = pending_oauth_login_path(config, model_provider);
    if let Ok(file) = std::fs::OpenOptions::new().write(true).open(&path) {
        let _ = file.set_len(0);
        let _ = file.sync_all();
    }

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Discard the stale pending state by deleting auth-<provider>-pending.json under the zeroclaw state dir, then re-run `zeroclaw auth login --model-provider <provider>`
  2. Keep the state dir and secret store (which decrypts encrypted_code_verifier) on the same machine/profile — moving only the JSON without the secret store makes the verifier unrecoverable
  3. Complete the paste-redirect step in the same session/environment where `auth login` started

Example fix

# before: resuming a stale pending login
zeroclaw auth paste-redirect --model-provider gemini

# after: clear it and start fresh
rm "$(zeroclaw auth state-dir)/auth-gemini-pending.json"
zeroclaw auth login --model-provider gemini
Defensive patterns

Strategy: validation

Validate before calling

let path = state_dir.join(format!("auth-{provider}-pending.json"));
if path.exists() {
    let raw: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(&path)?)?;
    let has_verifier = raw.get("encrypted_code_verifier").is_some_and(|v| !v.is_null())
        || raw.get("code_verifier").is_some_and(|v| !v.is_null());
    anyhow::ensure!(has_verifier, "pending login for {provider} lacks a code verifier — delete {path} and re-login");
}

Try / catch

match auth.load_pending_oauth_login(ctx, provider, profile).await {
    Ok(Some(p)) => Ok(p),
    Err(e) if e.to_string().contains("missing code verifier") => {
        let _ = std::fs::remove_file(pending_path); // clear stale state
        anyhow::bail!("pending login unusable — re-run `zeroclaw auth login --model-provider {provider}`");
    }
    other => other,
}

Prevention

When it happens

Trigger: Resuming (`auth paste-redirect`) a pending login whose state file was written by an older zeroclaw version before verifier persistence existed, a hand-crafted/truncated pending file, or a file where the encrypted field failed to serialize. paste_redirect hits this when loading the saved login.

Common situations: Upgrading zeroclaw across versions while a login was left half-finished, editing or partially copying the state dir, or disk issues truncating the JSON.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/40b9dec96a948486. Report an issue: GitHub.