{"record":{"id":"a0158bc0bb2bdf9b","repo":"vitessio/vitess","slug":"v-hook-failed-v-v","errorCode":null,"errorMessage":"%v hook failed(%v): %v","messagePattern":"(.+?) hook failed\\((.+?)\\): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/hook/hook.go","lineNumber":211,"sourceCode":"\n// Execute tries to execute the Hook and returns a HookResult.\nfunc (hook *Hook) Execute() (result *HookResult) {\n\treturn hook.ExecuteContext(context.Background())\n}\n\n// ExecuteOptional executes an optional hook, logs if it doesn't\n// exist, and returns a printable error.\nfunc (hook *Hook) ExecuteOptional() error {\n\thr := hook.Execute()\n\tswitch hr.ExitStatus {\n\tcase HOOK_DOES_NOT_EXIST:\n\t\tlog.Info(fmt.Sprintf(\"%v hook doesn't exist\", hook.Name))\n\tcase HOOK_VTROOT_ERROR:\n\t\tlog.Info(fmt.Sprintf(\"VTROOT not set, so %v hook doesn't exist\", hook.Name))\n\tcase HOOK_SUCCESS:\n\t\t// nothing to do here\n\tdefault:\n\t\treturn fmt.Errorf(\"%v hook failed(%v): %v\", hook.Name, hr.ExitStatus, hr.Stderr)\n\t}\n\treturn nil\n}\n\n// ExecuteAsWritePipe will execute the hook as in a Unix pipe,\n// directing output to the provided writer. It will return:\n// - an io.WriteCloser to write data to.\n// - a WaitFunc method to call to wait for the process to exit,\n// that returns stderr and the cmd.Wait() error.\n// - an error code and an error if anything fails.\nfunc (hook *Hook) ExecuteAsWritePipe(out io.Writer) (io.WriteCloser, WaitFunc, int, error) {\n\t// Find the hook.\n\tcmd, status, err := hook.findHook(context.Background())\n\tif err != nil {\n\t\treturn nil, nil, status, err\n\t}\n\n\t// Configure the process's stdin, stdout, and stderr.","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/hook/hook.go#L193-L229","documentation":"ExecuteOptional runs a hook and treats HOOK_DOES_NOT_EXIST / HOOK_VTROOT_ERROR / HOOK_SUCCESS as non-errors (hooks are optional), but any other exit status is returned as an error naming the hook, its exit status, and stderr. It means the hook script was found and executed but failed — its own stderr is embedded in the message.","triggerScenarios":"Calling hook.ExecuteOptional where the hook exists and runs but exits non-zero (e.g. HOOK_STAT_FAILED, HOOK_TERMINATED, or a script returning nonzero), or the process is killed by a signal.","commonSituations":"Hook scripts with bugs or unmet dependencies (missing commands inside the script); scripts failing due to wrong environment/arguments; hooks killed by timeouts.","solutions":["Read hook name, exit status, and stderr from the message to find why the script failed; fix the script or its inputs","Run the hook manually with the same arguments/environment to reproduce the failure","If the hook's absence should be tolerated but its failure shouldn't (or vice versa), use ExecuteOptional vs Execute appropriately"],"exampleFix":"// before: 'backup_hook hook failed(1): mysqldump: command not found'\n// after: install dependency in the image / fix script PATH\nRUN apt-get install -y mysql-client","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := hook.ExecuteOptional(h); err != nil {\n    // message contains: name, exit status, and the script's stderr\n    return fmt.Errorf(\"hook execution failed: %w\", err)\n}","preventionTips":["Test hook scripts standalone with the same arguments/environment used in production","Ensure all commands the script depends on exist in the Vitess runtime image","Include diagnostics in hook stderr so failures are self-explanatory"],"tags":["hook","exit-status","script"],"backgroundTag":"command-exited-nonzero","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}