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

  1. Install the hook script into $VTROOT/vthook/<name> (and make it executable)
  2. Verify the hook name spelling matches the script file name exactly
  3. 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

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


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/06dc19729a096e78. Report an issue: GitHub.