Troubleshooting
This page helps explain a failure, not just patch it. Open the troubleshooting overview
Hooks troubleshooting¶
When hook behavior looks wrong, the key is to distinguish between managed wrappers, foreign ownership, unsupported hook paths, and simple local drift. Most hook issues are understandable once you inspect them as a state problem.
What this page helps with¶
Use this page when:
- pre-commit no longer blocks staged secret material
- pre-push behavior changed unexpectedly
envctl hooks statusreports something unclear- a hook file exists but does not behave like
envctlused to - the repository seems to have multiple hook expectations at once
Start with status¶
Always start here:
$ envctl hooks status
Do not jump straight to reinstalling. First establish what envctl thinks the current hook state is.
How to read the common states¶
healthy¶
This means the managed wrapper is present and matches what envctl expects.
Usually, if behavior still feels wrong in this state, the issue is elsewhere:
- what you staged is not what you think you staged
- the hook did run, but the result was misunderstood
- another workflow layer is confusing the diagnosis
missing¶
This means the managed wrapper is not there.
Typical fix:
$ envctl hooks install
drifted¶
This means the hook looks like it used to be managed, but no longer matches the canonical wrapper.
Typical fix:
$ envctl hooks repair
foreign¶
This means some other implementation owns that supported hook name.
That is not automatically an error. It just means envctl is not currently the hook owner there.
Typical options:
- leave it alone if another hook system is intentionally in charge
- use
--forceonly if you intentionally want envctl to replace that ownership
not_executable¶
This means the hook exists but is not executable in the expected POSIX sense.
Typical fix:
$ envctl hooks repair
unsupported¶
This means the effective hooks path resolved by Git is outside the repository perimeter or otherwise not supported for envctl management.
That is a boundary decision, not a bug. envctl refuses to mutate hook locations it does not consider safely managed.
The most common hook problems¶
1. envctl init ran, but hooks are still not active¶
This usually means one of these:
- init completed, but managed hook installation did not converge
- another hook owner was already present
- the effective hooks path is unsupported
Check status first:
$ envctl hooks status
Then decide whether you need install, repair, or no action at all.
2. Hooks used to work, then stopped¶
This often points to drift or ownership change.
Typical path:
$ envctl hooks status
$ envctl hooks repair
$ envctl hooks status
3. Another tool is managing hooks¶
This is where people often overreact.
If another tool intentionally owns pre-commit or pre-push, then foreign is simply describing reality.
The real question is:
Which tool should own those supported hook names in this repository?
If the answer is “not envctl”, then no repair is needed.
If the answer is “envctl should own them again”, then a forced install or repair may be appropriate.
4. guard secrets behaves differently than expected¶
At that point, the issue may not be hook installation anymore.
It may be:
- the staged content is not what you think it is
- the files changed names or paths
- the hook runs, but the output is being misread
- the real issue is in
guard secrets, not in the wrapper
Test the underlying command directly:
$ envctl guard secrets
That helps separate hook-wrapper problems from guard-command problems.
Repair vs install¶
A simple rule:
- use
installwhen wrappers are missing and you want to place them - use
repairwhen wrappers exist but look wrong, drifted, or partially broken
When in doubt, status should tell you which one fits better.
When to use --force¶
Use --force only when you explicitly want envctl to replace foreign ownership for supported hook names.
That is not the normal path.
It is an intentional takeover.
If you are not sure whether you want to replace a foreign hook, you probably do not want --force yet.
A healthy hook workflow¶
A healthy repository usually looks like this:
envctl initattempts bootstrapenvctl hooks statusis readable and boring- managed wrappers stay canonical
guard secretscan also be run directly- CI still exists as a second line of defense
That is enough. Hook systems become fragile when they try to do too much.
Read next¶
Recovery¶
Use the broader recovery page if hooks are only one part of a bigger local setup issue.