vitessio/vitess · error
missing hook %v
Error message
missing hook %v
What it means
The hook name passed validation and SafePathJoin, but os.Stat found no file at <VTROOT>/vthook/<name>. findHook returns HOOK_DOES_NOT_EXIST with 'missing hook'. The name is legal; the script simply is not installed at the expected location.
Source
Thrown at go/vt/hook/hook.go:116
}
// findHook tries to locate the hook, and returns the exec.Cmd for it.
func (hook *Hook) findHook(ctx context.Context) (*exec.Cmd, int, error) {
// Find our root.
root, err := vtenv.VtRoot()
if err != nil {
return nil, HOOK_VTROOT_ERROR, fmt.Errorf("cannot get VTROOT: %v", err)
}
// See if the hook exists.
vthook, err := fileutil.SafePathJoin(filepath.Join(root, "vthook"), hook.Name)
if err != nil {
return nil, HOOK_INVALID_NAME, fmt.Errorf("invalid hook name %q: %v", hook.Name, err)
}
_, err = os.Stat(vthook)
if err != nil {
if os.IsNotExist(err) {
return nil, HOOK_DOES_NOT_EXIST, fmt.Errorf("missing hook %v", vthook)
}
return nil, HOOK_STAT_FAILED, fmt.Errorf("cannot stat hook %v: %v", vthook, err)
}
// Configure the command.
log.Info(fmt.Sprintf("hook: executing hook: %v %v", vthook, strings.Join(hook.Parameters, " ")))
cmd := exec.CommandContext(ctx, vthook, hook.Parameters...)
if len(hook.ExtraEnv) > 0 {
cmd.Env = os.Environ()
for key, value := range hook.ExtraEnv {
cmd.Env = append(cmd.Env, key+"="+value)
}
}
return cmd, HOOK_SUCCESS, nil
}
View on GitHub (pinned to 01a25a7d17)
Solutions
- Install the hook script into $VTROOT/vthook/<name> (and make it executable)
- Verify the hook name spelling matches the script file name exactly
- Confirm VTROOT points at the installation that actually contains the hook (echo $VTROOT; ls $VTROOT/vthook)
Example fix
// before: HOOK_DOES_NOT_EXIST for 'gc_backup' // after cp myhooks/gc_backup.sh $VTROOT/vthook/gc_backup chmod +x $VTROOT/vthook/gc_backup
Defensive patterns
Strategy: validation
Validate before calling
root, err := vtenv.VtRoot()
if err != nil { return err }
p, err := fileutil.SafePathJoin(filepath.Join(root, "vthook"), name)
if err != nil { return err }
if _, err := os.Stat(p); os.IsNotExist(err) {
return fmt.Errorf("hook %s not installed at %s", name, p)
} Try / catch
hr := hook.ExecuteOptional(h)
if hr.ExitStatus == hook.HOOK_DOES_NOT_EXIST {
log.Infof("hook %s not installed, skipping", h.Name)
return nil
} Prevention
- Deploy hook scripts to $VTROOT/vthook as part of provisioning (config-management managed)
- Check HOOK_DOES_NOT_EXIST exit status to treat missing hooks as skippable via ExecuteOptional
- Keep hook names consistent across all nodes of the cluster
When it happens
Trigger: Executing a hook whose name resolves to a nonexistent file under $VTROOT/vthook — hook never deployed, name typo, or wrong VTROOT pointing at an installation without that hook.
Common situations: Typos in hook names in vttablet/vtworker config; hooks deployed on some nodes but not others; VTROOT pointing to a different (older) installation lacking the script.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- cannot get VTROOT: %v
- invalid hook name %q: %v
- cannot stat hook %v: %v
- %v hook failed(%v): %v
- failed to configure stdin: %v
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/06dc19729a096e78.
Report an issue: GitHub.