{"record":{"id":"db09aca9f63d2a00","repo":"gitbutlerapp/gitbutler","slug":"no-ai-credentials-found-configure-in-gitbutler-se","errorCode":null,"errorMessage":"No AI credentials found. Configure in GitButler settings or set OPENAI_API_KEY environment variable.","messagePattern":"No AI credentials found\\. Configure in GitButler settings or set OPENAI_API_KEY environment variable\\.","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but/src/command/legacy/branch/show.rs","lineNumber":420,"sourceCode":"    author_email: String,\n    timestamp: i64,\n    files_changed: usize,\n    insertions: usize,\n    deletions: usize,\n    files: Vec<FileChange>,\n}\n\n#[instrument(skip(commits, git_config))]\nfn generate_branch_summary(\n    branch_name: &str,\n    commits: &[CommitInfo],\n    git_config: &gix::config::File,\n) -> anyhow::Result<String> {\n    use but_llm::LLMProvider;\n\n    // Get OpenAI provider (tries GitButler proxied, own key, then env var)\n    let llm = LLMProvider::from_git_config(git_config).ok_or_else(|| {\n        anyhow::anyhow!(\n            \"No AI credentials found. Configure in GitButler settings or set OPENAI_API_KEY environment variable.\"\n        )\n    })?;\n\n    // Build the prompt with commit information\n    let mut prompt = format!(\n        \"Please provide a concise summary (2-3 sentences) of what this branch '{branch_name}' accomplishes based on the following commits:\\n\\n\"\n    );\n\n    for commit in commits {\n        prompt.push_str(&format!(\"- {}: {}\\n\", commit.short_sha, commit.message));\n        if !commit.files.is_empty() {\n            prompt.push_str(\"  Files changed:\\n\");\n            for file in &commit.files {\n                prompt.push_str(&format!(\n                    \"    {} ({}, +{}, -{})\\n\",\n                    file.path, file.status, file.insertions, file.deletions\n                ));","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but/src/command/legacy/branch/show.rs#L402-L438","documentation":"generate_branch_summary builds an LLM prompt from a branch's commits; LLMProvider::from_git_config returns None when AI is unusable — per but-llm, that happens when the gitbutler.aiModelProvider setting is absent, the configured provider is unsupported, or provider init fails (e.g. bring-your-own-key chosen but no key resolvable, including the OPENAI_API_KEY env fallback). This anyhow error turns that Option into an explicit failure with setup guidance.","triggerScenarios":"Running `but branch show --summary` (summary generation) on a machine that never ran `but config` AI setup: no gitbutler.aiModelProvider in git config, no stored API key, and OPENAI_API_KEY unset. Also when the provider is set to a kind whose credentials expired/were removed.","commonSituations":"Fresh clone/CI machine expecting AI features without configuration; user configured Ollama but the local server isn't running so init fails; key removed from keychain/secret store after configuration.","solutions":["Run the AI configuration flow (`but config` → Select an AI provider) and provide credentials or pick GitButler API.","Or export OPENAI_API_KEY (the documented env-var fallback named in the message) and retry.","For local LLMs pick Ollama/LM Studio and ensure the server is reachable at its default port.","If you don't want AI summaries, run the command without the summary flag instead of fixing credentials."],"exampleFix":"# before\n$ but branch show feat --summary\nError: No AI credentials found. Configure in GitButler settings or set OPENAI_API_KEY environment variable.\n\n# after\n$ export OPENAI_API_KEY=sk-...\n$ but branch show feat --summary","handlingStrategy":"validation","validationCode":"// Check AI availability before requesting a summary\nuse but_llm::LLMProvider;\nif LLMProvider::from_git_config(&git_config).is_none() {\n    // skip the --summary flag or guide the user to `but config` AI setup\n    return print_plain_summary(commits);\n}","typeGuard":null,"tryCatchPattern":"match LLMProvider::from_git_config(git_config) {\n    Some(llm) => generate_summary(llm, commits).await,\n    None => print_plain_summary(commits), // degrade gracefully without AI\n}","preventionTips":["Run `but config` AI setup once per machine (or export OPENAI_API_KEY).","Make AI summaries optional in scripts so the command works without credentials."],"tags":["llm","credentials","openai","branch-summary"],"backgroundTag":"missing-api-key","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-23T11:17:13.642Z"}