{"record":{"id":"9205e168c20d9138","repo":"gitbutlerapp/gitbutler","slug":"when-using-anthropic-in-a-bring-your-own-key-confi","errorCode":null,"errorMessage":"When using Anthropic in a bring your own key configuration, you must provide a valid token","messagePattern":"When using Anthropic in a bring your own key configuration, you must provide a valid token","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/desktop/src/lib/ai/service.ts","lineNumber":356,"sourceCode":"\t\t\tconst openAIModelName = await this.getOpenAIModelName();\n\t\t\tconst openAIKey = await this.getOpenAIKey();\n\t\t\tconst openAICustomEndpoint = await this.getOpenAICustomEndpoint();\n\n\t\t\tif (!openAIKey) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"When using OpenAI 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 OpenAIClient(openAIKey, openAIModelName, openAICustomEndpoint);\n\t\t}\n\n\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","sourceCodeStart":338,"sourceCodeEnd":374,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/apps/desktop/src/lib/ai/service.ts#L338-L374","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Only pass refs you already know are remote-tracking, i.e. produced by iterating refs/remotes/*","Pre-check category_and_short_name() yourself and skip/handle non-RemoteBranch refs before calling for_ui","For upstream info of a local branch, resolve the branch's upstream/remote configuration first and pass that refs/remotes/... ref","If refs/remotes/<remote>/HEAD is involved, filter symbolic HEAD entries out of the list"],"exampleFix":"// before\nlet rt = RemoteTrackingReference::for_ui(ref_name, &remote_names)?;\n\n// after\nuse gix::refs::Category;\nif ref_name.category_and_short_name().map(|(c, _)| c) == Ok(Category::RemoteBranch) {\n    let rt = RemoteTrackingReference::for_ui(ref_name, &remote_names)?;\n}","handlingStrategy":"type-guard","validationCode":"use gix::refs::Category;\nif ref_name.category_and_short_name().map(|(c, _)| c) == Ok(Category::RemoteBranch) {\n    let rt = RemoteTrackingReference::for_ui(ref_name, &remote_names)?;\n}","typeGuard":"fn is_remote_tracking(ref_name: &gix::refs::FullName) -> bool {\n    matches!(ref_name.category_and_short_name(), Ok((gix::refs::Category::RemoteBranch, _)))\n}","tryCatchPattern":"match RemoteTrackingReference::for_ui(ref_name, &remote_names) {\n    Ok(rt) => { /* use rt */ }\n    Err(err) if err.to_string().contains(\"remote tracking branch\") => { /* skip non-remote ref */ }\n    Err(err) => return Err(err),\n}","preventionTips":["Only feed refs harvested from refs/remotes/* into for_ui","Filter out refs/remotes/<remote>/HEAD pseudo-refs when listing remote branches"],"tags":["rust","git","gitbutler","refs","remote-tracking-branch"],"backgroundTag":"invalid-git-ref-category","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-23T16:17:53.355Z"}