gitbutlerapp/gitbutler · error
Local AI configuration requires running inside a git…
Error message
Local AI configuration requires running inside a git repository
What it means
The `but config` command supports local (repo-scoped) and global AI configuration. When `ai_config` is invoked without a repository context (the caller passes None as the project/repository handle), local-scope configuration is impossible because there is no repo-local config file to write to, so the CLI aborts with this bail. Use global scope instead, or run from inside a git repository.
Solutions
- Run the command from inside a git repository (cd into your project work tree) and retry with --local
- Drop the --local flag so configuration is written globally instead
- Initialize a git repository in the current directory (git init) if a repo-local setting is truly needed
Example fix
// before but config ai --local --api-key sk-... // after cd /path/to/repo && but config ai --local --api-key sk-... # or, scope-independent: but config ai --api-key sk-...
Defensive patterns
Strategy: validation
Validate before calling
function isInsideGitRepo(dir) {
try {
require('node:child_process').execSync('git rev-parse --is-inside-work-tree', { cwd: dir, stdio: 'pipe' });
return true;
} catch { return false; }
}
if (!isInsideGitRepo(process.cwd()) && args.includes('--local')) throw new Error('Run from inside a git repo or drop --local'); Type guard
const isLocalScope = (opts) => opts.local === true;
Try / catch
try {
await exec('but config ai --local ...');
} catch (e) {
if (e.message.includes('requires running inside a git repository')) {
// fallback to global config
await exec('but config ai ...');
} else throw e;
} Prevention
- Always cd into the repository before repo-scoped CLI commands
- Detect non-repo directories in scripts and skip/scope-down --local flags
- Use git rev-parse in CI before invoking repo-scoped commands
When it happens
Trigger: Running `but config ai --local ...` (or an AiSubcommand with local=true) from outside any git work tree, so no project/repository can be resolved and ai_config is called with a None repo path.
Common situations: Developers running the CLI in a home directory, CI workspace, or temp folder that is not a git repo while trying to set a repo-local AI API key; scripts that cd away from the repo before invoking but config.
Understand the failure class
Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.
Related errors
- No target branch is configured and none could be inferred…
- Aborting due to empty branch name
- Bare repositories are not supported.
- Branch ' ' not found
- Branch ' ' not found when checking for conflicts
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/f3ab0d1751c5a8c2.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but/src/command/config.rs:117
Some(Subcommands::Feature { flag, status }) => feature_config(out, flag, status),
Some(Subcommands::Ai { local, global, cmd }) => {
ai_config_with_repo(ctx, out, cmd, local, global)
}
None => show_overview(ctx, out).await,
}
}
/// Handle AI config subcommand without repository context.
///
/// This supports global configuration from outside of a git repository.
pub(crate) fn ai_config(
out: &mut OutputChannel,
cmd: Option<AiSubcommand>,
local: bool,
global: bool,
) -> Result<()> {
if local {
anyhow::bail!("Local AI configuration requires running inside a git repository")
}
ai_config_inner(None, out, cmd, local, global)
}
/// Show overview of important settings
async fn show_overview(ctx: &mut Context, out: &mut OutputChannel) -> Result<()> {
let t = theme::get();
#[derive(Serialize)]
struct ConfigOverview {
name: Option<String>,
email: Option<String>,
editor: Option<String>,
target_branch: Option<String>,
forge_accounts: Vec<ForgeAccountInfo>,
}
#[derive(Serialize)]
struct ForgeAccountInfo {View on GitHub (pinned to 58e5313667)