gitbutlerapp/gitbutler · error

No authenticated forge users found. Run

Error message

No authenticated forge users found.
Run '{}' to authenticate with {}.

What it means

This error is thrown by ensure_forge_authentication when no forge account credentials exist at all (ForgeAccountValidity::NoCredentials). GitButler knows the repository targets a forge but has no authenticated user to act on behalf of, so review/merge commands abort with the remediation command in the message.

Solutions

  1. Run `but config forge auth` to authenticate with the forge
  2. Confirm the detected forge (GitHub/GitLab/Bitbucket) matches the repository's remote and that you authenticated against that forge
  3. In non-interactive environments, run the auth command once interactively so credentials are stored, then retry

Example fix

// before
but forge review create ...
// error: No authenticated forge users found.
// after
but config forge auth
but forge review create ...
Defensive patterns

Strategy: validation

Validate before calling

// ensure credentials exist before forge operations
if !but config forge status 2>/dev/null; then
  but config forge auth
fi

Type guard

function isNoCredentialsError(e: Error): boolean {
  return /No authenticated forge users found/i.test(e.message);
}

Try / catch

try {
  await runBut(['forge', 'review', 'create']);
} catch (e) {
  if (/No authenticated forge users/.test(e.message)) {
    throw new Error('Run `but config forge auth` first', { cause: e });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling enable_auto_merge, set_draftiness, or create_review before ever running forge authentication on this machine, or after credentials were cleared/removed from GitButler's config.

Common situations: Fresh installs or new machines, CI containers without interactive auth, users who cleared app data, or contributors who cloned a repo whose forge differs from their previously authenticated one.

Understand the failure class

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/4e806e5e9319fc12. Report an issue: GitHub.

Appendix: source

Thrown at crates/but/src/command/legacy/forge/review.rs:416

        but_forge::check_forge_account_is_valid(preferred_forge_user, &forge_repo_info, &storage)
            .await?;

    let forge_display_name = match forge_repo_info.forge {
        but_forge::ForgeName::Azure => {
            anyhow::bail!("Azure is unsupported at the minute. Sorry 😞.");
        }
        but_forge::ForgeName::GitHub => "GitHub",
        but_forge::ForgeName::GitLab => "GitLab",
        but_forge::ForgeName::Bitbucket => "Bitbucket",
    };

    match account_validity {
        but_forge::ForgeAccountValidity::Invalid => Err(anyhow::anyhow!(
            "Known account is not correctly authenticated.\nRun '{}' to authenticate with {}.",
            "but config forge auth",
            forge_display_name
        )),
        but_forge::ForgeAccountValidity::NoCredentials => Err(anyhow::anyhow!(
            "No authenticated forge users found.\nRun '{}' to authenticate with {}.",
            "but config forge auth",
            forge_display_name
        )),
        but_forge::ForgeAccountValidity::Valid => {
            // All good, continue
            Ok(())
        }
    }
}

/// Get list of branch names that don't have PRs yet.
fn get_branches_without_prs(
    review_map: &std::collections::HashMap<String, Vec<but_forge::ForgeReview>>,
    applied_stacks: &[HeadInfoStack],
) -> anyhow::Result<Vec<String>> {
    let mut branches_without_prs = Vec::new();
    for stack_entry in applied_stacks {

View on GitHub (pinned to 58e5313667)