vitessio/vitess · error
cannot stat hook %v: %v
Error message
cannot stat hook %v: %v
What it means
os.Stat on the resolved hook path failed with an error other than NotExist (e.g. permission denied on a directory component, I/O error, or the path is not traversable). findHook returns HOOK_STAT_FAILED. Unlike HOOK_DOES_NOT_EXIST, the file may exist but cannot be inspected.
Source
Thrown at go/vt/hook/hook.go:119
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
}
// ExecuteContext tries to execute the Hook with the given context and returns a HookResult.
func (hook *Hook) ExecuteContext(ctx context.Context) (result *HookResult) {
result = &HookResult{}View on GitHub (pinned to 01a25a7d17)
Solutions
- Fix filesystem permissions so the Vitess process can stat the hook path (chmod/chown the vthook dir and scripts)
- Inspect the trailing %v (the raw os.Stat error) to identify the exact OS-level cause
- Check for broken symlinks or a partially-deployed vthook directory and redeploy the hook
Example fix
// before: cannot stat hook: permission denied // after sudo chmod o+x $VTROOT/vthook sudo chmod +x $VTROOT/vthook/myhook
Defensive patterns
Strategy: validation
Validate before calling
p := filepath.Join(os.Getenv("VTROOT"), "vthook", name)
if _, err := os.Stat(p); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("cannot access hook %s: %v", p, err)
} Try / catch
hr := h.ExecuteContext(ctx)
if hr.ExitStatus == hook.HOOK_STAT_FAILED {
return fmt.Errorf("hook %s unusable (stat failed): %s", h.Name, hr.Stderr)
} Prevention
- Ensure the Vitess process user owns or can traverse $VTROOT/vthook
- Make hook scripts executable and avoid broken symlinks
- Monitor the wrapped os.Stat error in logs for filesystem problems
When it happens
Trigger: Executing a hook when os.Stat on <VTROOT>/vthook/<name> returns a non-IsNotExist error — permission denied on vthook dir or file, broken symlink traversal errors, or filesystem I/O failures.
Common situations: vthook directory or script owned by another user without execute permission; NFS/permission misconfiguration in containers; corrupted symlink left by a failed deploy.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- unable to create file: %v
- could not create temp file: %v
- could not read existing file %v: %v
- could not back up existing %v: %v
- failure creating directory %s: %w
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/3043fb3b93ab2e79.
Report an issue: GitHub.