{"record":{"id":"37e1b2acce3fbab2","repo":"nikivdev/code","slug":"refusing-to-remove-non-flow-hook-at","errorCode":null,"errorMessage":"Refusing to remove non-Flow hook at {}.","messagePattern":"Refusing to remove non-Flow hook at (.+?)\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/push_hook.rs","lineNumber":120,"sourceCode":"    }\n\n    git_config_global_set(\"core.hooksPath\", &hooks_path)?;\n    println!(\"Installed Flow pre-push hook at {}\", hook_path.display());\n    println!(\"Global core.hooksPath -> {}\", hooks_path.display());\n    Ok(())\n}\n\npub fn uninstall_hooks() -> Result<()> {\n    let hooks_path = push_policy::effective_global_hooks_path()?;\n    let hook_path = hooks_path.join(\"pre-push\");\n    let current_hooks_path = current_global_hooks_path()?;\n\n    if hook_path.exists() && is_flow_managed_hook(&hook_path)? {\n        fs::remove_file(&hook_path)\n            .with_context(|| format!(\"failed to remove {}\", hook_path.display()))?;\n        println!(\"Removed Flow pre-push hook at {}\", hook_path.display());\n    } else if hook_path.exists() {\n        bail!(\n            \"Refusing to remove non-Flow hook at {}.\",\n            hook_path.display()\n        );\n    } else {\n        println!(\"No Flow pre-push hook found at {}\", hook_path.display());\n    }\n\n    if let Some(current) = current_hooks_path\n        && normalize_path(&current) == normalize_path(&hooks_path)\n    {\n        git_config_global_unset(\"core.hooksPath\")?;\n        println!(\"Unset global core.hooksPath\");\n    }\n\n    Ok(())\n}\n\npub fn print_hook_status() -> Result<()> {","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/push_hook.rs#L102-L138","documentation":"`uninstall_hooks` refuses to delete a pre-push hook file that exists but does not contain the Flow marker (`is_flow_managed_hook` checks for FLOW_PRE_PUSH_HOOK_MARKER). The library deliberately avoids destroying hook files it did not create, since they may belong to other tools or hand-written scripts.","triggerScenarios":"Running `uninstall_hooks` (via `run_hooks_command` uninstall) when `<hooks>/pre-push` exists but was authored by something else — e.g. installed by husky, pre-commit, or manually — so its content lacks the Flow marker.","commonSituations":"Previously used husky or the `pre-commit` framework; another tool rewrote or replaced the hook after Flow installed it; a developer hand-edited the hook and removed the marker comment; switching hook managers on the same machine.","solutions":["Inspect the hook file at the printed path and remove it manually if it is truly not needed: `rm <path-to>/pre-push`","Back up the hook content, remove the file, re-run uninstall, then re-create your custom hook","Reinstall the Flow hook (`push hooks install --force`) then uninstall, if the hook is actually Flow's but the marker was edited out","Point git's core.hooksPath elsewhere with `git config --global --unset core.hooksPath` and manage hooks independently"],"exampleFix":"// before (manual removal)\n$ f push hooks uninstall\nError: Refusing to remove non-Flow hook at /home/user/.flow/hooks/pre-push.\n// after\n$ grep -v FLOW /home/user/.flow/hooks/pre-push  # inspect: it's a husky script\n$ rm /home/user/.flow/hooks/pre-push\n$ f push hooks uninstall  # now reports 'No Flow pre-push hook found'","handlingStrategy":"validation","validationCode":"// preflight: only uninstall if the hook is Flow-managed\nuse std::fs;\nfn flow_managed(hook: &std::path::Path, marker: &str) -> anyhow::Result<bool> {\n    Ok(hook.exists() && fs::read_to_string(hook)?.contains(marker))\n}\nif !flow_managed(&hook_path, FLOW_PRE_PUSH_HOOK_MARKER)? {\n    eprintln!(\"skipping uninstall: {} is not Flow-managed\", hook_path.display());\n}","typeGuard":"fn is_flow_managed(hook: &std::path::Path, marker: &str) -> bool {\n    std::fs::read_to_string(hook).map(|c| c.contains(marker)).unwrap_or(false)\n}","tryCatchPattern":"match uninstall_hooks() {\n    Ok(()) => {},\n    Err(e) if e.to_string().contains(\"Refusing to remove non-Flow hook\") => {\n        eprintln!(\"hook not managed by Flow; remove manually if desired\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Run the tool's hook status command before install/uninstall to see if the hook is Flow-managed","Don't hand-edit the generated pre-push hook; the marker comment is Flow's ownership check","Migrate other hook managers (husky/pre-commit) off the same core.hooksPath before using this tool","Back up custom hook scripts before touching hooks"],"tags":["git","hooks","filesystem","safety-guard"],"backgroundTag":"non-managed-hook-refused","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}