{"record":{"id":"3043fb3b93ab2e79","repo":"vitessio/vitess","slug":"cannot-stat-hook-v-v","errorCode":null,"errorMessage":"cannot stat hook %v: %v","messagePattern":"cannot stat hook (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/hook/hook.go","lineNumber":119,"sourceCode":"func (hook *Hook) findHook(ctx context.Context) (*exec.Cmd, int, error) {\n\t// Find our root.\n\troot, err := vtenv.VtRoot()\n\tif err != nil {\n\t\treturn nil, HOOK_VTROOT_ERROR, fmt.Errorf(\"cannot get VTROOT: %v\", err)\n\t}\n\n\t// See if the hook exists.\n\tvthook, err := fileutil.SafePathJoin(filepath.Join(root, \"vthook\"), hook.Name)\n\tif err != nil {\n\t\treturn nil, HOOK_INVALID_NAME, fmt.Errorf(\"invalid hook name %q: %v\", hook.Name, err)\n\t}\n\t_, err = os.Stat(vthook)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn nil, HOOK_DOES_NOT_EXIST, fmt.Errorf(\"missing hook %v\", vthook)\n\t\t}\n\n\t\treturn nil, HOOK_STAT_FAILED, fmt.Errorf(\"cannot stat hook %v: %v\", vthook, err)\n\t}\n\n\t// Configure the command.\n\tlog.Info(fmt.Sprintf(\"hook: executing hook: %v %v\", vthook, strings.Join(hook.Parameters, \" \")))\n\tcmd := exec.CommandContext(ctx, vthook, hook.Parameters...)\n\tif len(hook.ExtraEnv) > 0 {\n\t\tcmd.Env = os.Environ()\n\t\tfor key, value := range hook.ExtraEnv {\n\t\t\tcmd.Env = append(cmd.Env, key+\"=\"+value)\n\t\t}\n\t}\n\n\treturn cmd, HOOK_SUCCESS, nil\n}\n\n// ExecuteContext tries to execute the Hook with the given context and returns a HookResult.\nfunc (hook *Hook) ExecuteContext(ctx context.Context) (result *HookResult) {\n\tresult = &HookResult{}","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/hook/hook.go#L101-L137","documentation":"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.","triggerScenarios":"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.","commonSituations":"vthook directory or script owned by another user without execute permission; NFS/permission misconfiguration in containers; corrupted symlink left by a failed deploy.","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"],"exampleFix":"// before: cannot stat hook: permission denied\n// after\nsudo chmod o+x $VTROOT/vthook\nsudo chmod +x $VTROOT/vthook/myhook","handlingStrategy":"validation","validationCode":"p := filepath.Join(os.Getenv(\"VTROOT\"), \"vthook\", name)\nif _, err := os.Stat(p); err != nil && !os.IsNotExist(err) {\n    return fmt.Errorf(\"cannot access hook %s: %v\", p, err)\n}","typeGuard":null,"tryCatchPattern":"hr := h.ExecuteContext(ctx)\nif hr.ExitStatus == hook.HOOK_STAT_FAILED {\n    return fmt.Errorf(\"hook %s unusable (stat failed): %s\", h.Name, hr.Stderr)\n}","preventionTips":["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"],"tags":["hook","permissions","filesystem"],"backgroundTag":"permission-denied","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}