gitbutlerapp/gitbutler · error

When using OpenRouter, you must provide a valid API key

Error message

When using OpenRouter, you must provide a valid API key

What it means

integrate_upstream (the function behind upstream integration) refuses to operate when the workspace is an AdHoc workspace whose ref_name() is None - which is exactly the state of a repository with a detached HEAD and no workspace ref to anchor onto. Integration needs a named target ref to compute and update the workspace.

Source

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

		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");
		}

		return undefined;
	}

	async summarizeCommit({
		diffInput,
		useHaiku = false,
		useEmojiStyle = false,
		useExtraConciseStyle = false,
		commitTemplate,
		onToken,
		branchName,
	}: SummarizeCommitOpts): Promise<string | undefined> {
		const aiClient = await this.buildClient();

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Attach HEAD to a branch first: git switch <branch> (or git switch -c <new-branch>), then rerun the integration
  2. Create/point the workspace at a ref so workspace.ref_name() is Some before calling the API
  3. In tooling, detect detached HEAD (repo.head_kind()/HEAD is peeled to an id with no reference) and disable or redirect the integrate-upstream action

Example fix

# shell
# before: HEAD is detached
git checkout main   # or git switch -
# after: rerun the upstream integration
Defensive patterns

Strategy: validation

Validate before calling

// guard: refuse to integrate upstream while HEAD is detached
use gix::head::Kind;
if repo.head().ok().and_then(|h| h.referent_name().is_none().then_some(h))
    .map(|h| h.kind == Kind::Detached) == Some(true) {
    anyhow::bail!("attach HEAD to a branch before integrating upstream");
}

Try / catch

if let Err(err) = integrate_upstream(...) {
    if err.to_string().contains("detached") {
        // prompt: git switch <branch>, then retry
    } else { return Err(err); }
}

Prevention

When it happens

Trigger: Running an upstream integration (e.g. but workspace update flows) while HEAD is detached or otherwise unnamed in an ad-hoc workspace: workspace.kind == WorkspaceKind::AdHoc and workspace.ref_name() returns None.

Common situations: User checked out a commit directly (git checkout <sha>), CI jobs that start detached, rebase/conflict states that detach HEAD, or scripts operating on repos initialized without branches. The app then offers 'integrate upstream' which has no ref to integrate into.

Related errors


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