{"record":{"id":"c427ff4edc46881b","repo":"gitbutlerapp/gitbutler","slug":"when-using-openrouter-you-must-provide-a-valid-ap","errorCode":null,"errorMessage":"When using OpenRouter, you must provide a valid API key","messagePattern":"When using OpenRouter, you must provide a valid API key","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/desktop/src/lib/ai/service.ts","lineNumber":369,"sourceCode":"\t\tif (modelKind === ModelKind.Anthropic) {\n\t\t\tconst anthropicModelName = await this.getAnthropicModelName();\n\t\t\tconst anthropicKey = await this.getAnthropicKey();\n\n\t\t\tif (!anthropicKey) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"When using Anthropic in a bring your own key configuration, you must provide a valid token\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn new AnthropicAIClient(anthropicKey, anthropicModelName);\n\t\t}\n\n\t\tif (modelKind === ModelKind.OpenRouter) {\n\t\t\tconst openRouterKey = (await this.getOpenRouterKey())?.trim();\n\t\t\tconst openRouterModelName = await this.getOpenRouterModelName();\n\n\t\t\tif (!openRouterKey) {\n\t\t\t\tthrow new Error(\"When using OpenRouter, you must provide a valid API key\");\n\t\t\t}\n\n\t\t\treturn new OpenAIClient(openRouterKey, openRouterModelName, \"https://openrouter.ai/api/v1\");\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tasync summarizeCommit({\n\t\tdiffInput,\n\t\tuseHaiku = false,\n\t\tuseEmojiStyle = false,\n\t\tuseExtraConciseStyle = false,\n\t\tcommitTemplate,\n\t\tonToken,\n\t\tbranchName,\n\t}: SummarizeCommitOpts): Promise<string | undefined> {\n\t\tconst aiClient = await this.buildClient();","sourceCodeStart":351,"sourceCodeEnd":387,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/apps/desktop/src/lib/ai/service.ts#L351-L387","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Attach HEAD to a branch first: git switch <branch> (or git switch -c <new-branch>), then rerun the integration","Create/point the workspace at a ref so workspace.ref_name() is Some before calling the API","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"],"exampleFix":"# shell\n# before: HEAD is detached\ngit checkout main   # or git switch -\n# after: rerun the upstream integration","handlingStrategy":"validation","validationCode":"// guard: refuse to integrate upstream while HEAD is detached\nuse gix::head::Kind;\nif repo.head().ok().and_then(|h| h.referent_name().is_none().then_some(h))\n    .map(|h| h.kind == Kind::Detached) == Some(true) {\n    anyhow::bail!(\"attach HEAD to a branch before integrating upstream\");\n}","typeGuard":null,"tryCatchPattern":"if let Err(err) = integrate_upstream(...) {\n    if err.to_string().contains(\"detached\") {\n        // prompt: git switch <branch>, then retry\n    } else { return Err(err); }\n}","preventionTips":["Disable the integrate-upstream action when HEAD is detached","In CI/scripts, always start from a named branch before workspace updates"],"tags":["rust","git","gitbutler","detached-head","workspace","rebase"],"backgroundTag":"detached-head-operation","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}