gitbutlerapp/gitbutler · error · anyhow::Error

Preferred GitLab account '{account}' has not authenticated y

Error message

Preferred GitLab account '{account}' has not authenticated yet.\nRun 'but config forge auth' to authenticate, or choose another account.

What it means

Thrown by resolve_account when a preferred GitLab account was explicitly requested but it is not among the accounts known to but-forge storage. The identifier is compared against the token store's account list; any mismatch — typo, different casing/format, or the account simply never completed auth on this machine — bails. Unlike the no-accounts error, valid accounts exist; the requested one just is not one of them.

Source

Thrown at crates/but-gitlab/src/client.rs:1087

    let target_project_id = target_project_id.unwrap_or(project_id);
    source_project_id != target_project_id
}

pub(crate) fn resolve_account(
    preferred_account: Option<&crate::GitlabAccountIdentifier>,
    storage: &but_forge_storage::Controller,
) -> Result<crate::GitlabAccountIdentifier, anyhow::Error> {
    let known_accounts = crate::token::list_known_gitlab_accounts(storage)?;
    let Some(default_account) = known_accounts.first() else {
        bail!(
            "No authenticated GitLab users found.\nRun 'but config forge auth' to authenticate with GitLab."
        );
    };
    let account = if let Some(account) = preferred_account {
        if known_accounts.contains(account) {
            account
        } else {
            bail!(
                "Preferred GitLab account '{account}' has not authenticated yet.\nRun 'but config forge auth' to authenticate, or choose another account."
            );
        }
    } else {
        default_account
    };

    Ok(account.to_owned())
}

#[cfg(test)]
mod tests {
    use super::{
        GitLabMergeRequest, GitLabPipelineJob, GitLabPipelineRef, MAX_MERGE_REQUEST_REQUESTS,
        MergeRequest, merge_request_page_is_safe, next_page_from_headers, normalize_pipeline_jobs,
        repo_owner_from_path_with_namespace, update_draft_state_in_title,
    };
    use reqwest::header::{HeaderMap, HeaderValue};

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Run `but config forge auth` and authenticate specifically as that account, then retry
  2. List the authenticated accounts and use one of those identifiers instead (or pass None to take the default)
  3. If the GitLab account name/email changed, re-auth to refresh the stored identifier and update the preference to match
  4. Check for casing/whitespace differences between the preferred identifier and the stored one

Example fix

// before
let account = resolve_account(Some(&preferred), &storage)?; // unknown handle aborts

// after: fall back to the default account with a warning
let account = match resolve_account(Some(&preferred), &storage) {
    Ok(account) => account,
    Err(err) if err.to_string().contains("has not authenticated yet") => {
        tracing::warn!(%preferred, "account not authenticated; using default");
        resolve_account(None, &storage)?
    }
    Err(err) => return Err(err),
};
Defensive patterns

Strategy: validation

Validate before calling

// Validate the preferred account against the store before calling Git APIs
let known = but_gitlab::token::list_known_gitlab_accounts(&storage)?;
let account = match preferred_account.filter(|a| known.contains(a)) {
    Some(a) => a.clone(),
    None => known.first().cloned().context("no GitLab accounts authenticated")?, // fall back to default
};

Try / catch

match resolve_account(Some(&preferred), &storage) {
    Ok(account) => Ok(account),
    Err(err) if err.to_string().contains("has not authenticated yet") => {
        tracing::warn!(%preferred, "not authenticated; falling back to default account");
        resolve_account(None, &storage)
    }
    Err(err) => Err(err),
}

Prevention

When it happens

Trigger: Calling a GitLab API with preferred_account = Some(&identifier) where identifier is a handle that never ran `but config forge auth` on this machine; the account's name/email changed on GitLab so the stored identifier differs from the configured one; configuration copied between machines that authenticated different accounts; casing or formatting mismatch in the stored preference.

Common situations: Multi-account users (work + personal) with a stale default in settings; dotfiles/config synced across machines where only one machine authenticated the second account; rename on GitLab.com breaking a stored identifier.

Understand the failure class

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/877b2fa2b607a999. Report an issue: GitHub.