{"record":{"id":"8a5b4832d128a246","repo":"gitbutlerapp/gitbutler","slug":"remote-head-for-remote-name-is-not-symbolic","errorCode":null,"errorMessage":"Remote HEAD for {remote_name} is not symbolic","messagePattern":"Remote HEAD for (.+?) is not symbolic","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-action/src/lib.rs","lineNumber":158,"sourceCode":"fn default_target_setting_if_none(ctx: &Context) -> anyhow::Result<()> {\n    if ctx.project_meta()?.target_ref.is_some() {\n        return Ok(());\n    }\n    // Lets do the equivalent of `git symbolic-ref refs/remotes/origin/HEAD --short` to guess the default target.\n\n    let repo = ctx.repo.get()?;\n    let remote_name = repo\n        .remote_default_name(gix::remote::Direction::Push)\n        .ok_or_else(|| anyhow::anyhow!(\"No push remote set or more than one remote\"))?\n        .to_string();\n\n    let mut head_ref = repo\n        .find_reference(&format!(\"refs/remotes/{remote_name}/HEAD\"))\n        .map_err(|_| anyhow::anyhow!(\"No HEAD reference found for remote {remote_name}\"))?;\n    let target_ref_name = head_ref\n        .target()\n        .try_name()\n        .ok_or_else(|| anyhow::anyhow!(\"Remote HEAD for {remote_name} is not symbolic\"))?\n        .to_owned();\n\n    let head_commit = head_ref.peel_to_commit()?;\n\n    ctx.set_project_meta(ProjectMeta {\n        target_ref: Some(target_ref_name),\n        target_commit_id: Some(head_commit.id),\n        push_remote: None,\n    })?;\n    Ok(())\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, EnumString, Default)]\n#[serde(rename_all = \"camelCase\")]\npub enum ActionHandler {\n    #[default]\n    HandleChangesSimple,\n}","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/2497b8007aa4a1922dae9a805b32ffe5b5037785/crates/but-action/src/lib.rs#L140-L176","documentation":"The remote HEAD reference exists but head_ref.target().try_name() returned None, meaning refs/remotes/<remote>/HEAD is a plain ref pointing directly at an object id instead of symbolically aliasing refs/remotes/<remote>/<branch>. GitButler needs the symbolic form to derive the default target branch name, so default_target_setting_if_none bails.","triggerScenarios":"default_target_setting_if_none on a repo where refs/remotes/<remote>/HEAD was written as a direct ref — e.g. via `git update-ref refs/remotes/origin/HEAD <sha>`, or created by mirror/backup tooling that materializes symrefs as plain refs.","commonSituations":"Repos restored from bundles or mirror clones where symrefs became direct refs; scripts pinning remote HEAD with update-ref; migration tooling copying refs verbatim.","solutions":["Recreate it as a symref: git update-ref -d refs/remotes/<remote>/HEAD && git remote set-head <remote> --auto.","Or point it at the branch directly: git remote set-head <remote> <branch>.","Or configure GitButler's target branch explicitly so the guess path is skipped.","Check the current form with git symbolic-ref refs/remotes/<remote>/HEAD — it errors on non-symbolic refs."],"exampleFix":"git update-ref -d refs/remotes/origin/HEAD\ngit remote set-head origin --auto\ngit symbolic-ref refs/remotes/origin/HEAD  # -> refs/remotes/origin/main","handlingStrategy":"validation","validationCode":"fn remote_head_is_symbolic(repo: &gix::Repository, remote: &str) -> bool {\n    repo.find_reference(&format!(\"refs/remotes/{remote}/HEAD\"))\n        .ok()\n        .and_then(|r| r.target().try_name().map(|_| true))\n        .unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never write refs/remotes/<remote>/HEAD with update-ref; use git remote set-head.","Validate the symref shape when onboarding a repo into GitButler.","Prefer an explicitly configured target_ref over the discovery path."],"tags":["git-remote","remote-head","symbolic-ref","target-branch"],"backgroundTag":"non-symbolic-remote-head","analyzedSha":"2497b8007aa4a1922dae9a805b32ffe5b5037785","analyzedAt":"2026-08-17T00:30:25.648Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}