gitbutlerapp/gitbutler · error

When using Anthropic in a bring your own key configuration,

Error message

When using Anthropic in a bring your own key configuration, you must provide a valid token

What it means

RemoteTrackingReference::for_ui parses a full ref name by asking gix for its category and requires Category::RemoteBranch (refs/remotes/<remote>/<name>). Any other ref shape - a local branch (refs/heads/...), tag, note, or a remote HEAD symbolic ref - fails the expectation immediately.

Source

Thrown at apps/desktop/src/lib/ai/service.ts:356

			const openAIModelName = await this.getOpenAIModelName();
			const openAIKey = await this.getOpenAIKey();
			const openAICustomEndpoint = await this.getOpenAICustomEndpoint();

			if (!openAIKey) {
				throw new Error(
					"When using OpenAI in a bring your own key configuration, you must provide a valid token",
				);
			}

			return new OpenAIClient(openAIKey, openAIModelName, openAICustomEndpoint);
		}

		if (modelKind === ModelKind.Anthropic) {
			const anthropicModelName = await this.getAnthropicModelName();
			const anthropicKey = await this.getAnthropicKey();

			if (!anthropicKey) {
				throw new Error(
					"When using Anthropic in a bring your own key configuration, you must provide a valid token",
				);
			}

			return new AnthropicAIClient(anthropicKey, anthropicModelName);
		}

		if (modelKind === ModelKind.OpenRouter) {
			const openRouterKey = (await this.getOpenRouterKey())?.trim();
			const openRouterModelName = await this.getOpenRouterModelName();

			if (!openRouterKey) {
				throw new Error("When using OpenRouter, you must provide a valid API key");
			}

			return new OpenAIClient(openRouterKey, openRouterModelName, "https://openrouter.ai/api/v1");
		}

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Only pass refs you already know are remote-tracking, i.e. produced by iterating refs/remotes/*
  2. Pre-check category_and_short_name() yourself and skip/handle non-RemoteBranch refs before calling for_ui
  3. For upstream info of a local branch, resolve the branch's upstream/remote configuration first and pass that refs/remotes/... ref
  4. If refs/remotes/<remote>/HEAD is involved, filter symbolic HEAD entries out of the list

Example fix

// before
let rt = RemoteTrackingReference::for_ui(ref_name, &remote_names)?;

// after
use gix::refs::Category;
if ref_name.category_and_short_name().map(|(c, _)| c) == Ok(Category::RemoteBranch) {
    let rt = RemoteTrackingReference::for_ui(ref_name, &remote_names)?;
}
Defensive patterns

Strategy: type-guard

Validate before calling

use gix::refs::Category;
if ref_name.category_and_short_name().map(|(c, _)| c) == Ok(Category::RemoteBranch) {
    let rt = RemoteTrackingReference::for_ui(ref_name, &remote_names)?;
}

Type guard

fn is_remote_tracking(ref_name: &gix::refs::FullName) -> bool {
    matches!(ref_name.category_and_short_name(), Ok((gix::refs::Category::RemoteBranch, _)))
}

Try / catch

match RemoteTrackingReference::for_ui(ref_name, &remote_names) {
    Ok(rt) => { /* use rt */ }
    Err(err) if err.to_string().contains("remote tracking branch") => { /* skip non-remote ref */ }
    Err(err) => return Err(err),
}

Prevention

When it happens

Trigger: Calling RemoteTrackingReference::for_ui(ref_name, remote_names) with a gix::refs::FullName that is not under refs/remotes/, e.g. a workspace segment ref passed by mistake, or refs/remotes/origin/HEAD whose category parses differently than expected.

Common situations: Frontend code mapping arbitrary selected refs into remote-tracking info; upstream integrations handing over the target workspace ref instead of its upstream; recent gix version changes to category classification of pseudo-refs like refs/remotes/<remote>/HEAD.

Related errors


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