vitessio/vitess · error
cannot get VTROOT: %v
Error message
cannot get VTROOT: %v
What it means
Hook.Lookup resolves the VTROOT environment directory to find where vthook binaries live. When vtenv.VtRoot() cannot determine the Vitess root directory, findHook returns HOOK_VTROOT_ERROR with this message. It means the hook could not even be located because the installation root is unknown, not that a specific hook is missing.
Source
Thrown at go/vt/hook/hook.go:105
return &Hook{Name: name, Parameters: params}
}
// NewSimpleHook returns a Hook object with just a name.
func NewSimpleHook(name string) *Hook {
return &Hook{Name: name}
}
// NewHookWithEnv returns a Hook object with the provided name, params and ExtraEnv.
func NewHookWithEnv(name string, params []string, env map[string]string) *Hook {
return &Hook{Name: name, Parameters: params, ExtraEnv: env}
}
// 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, " ")))View on GitHub (pinned to 01a25a7d17)
Solutions
- Set the VTROOT environment variable to the Vitess installation root before starting the process
- Run the binary from within a proper Vitess distribution so vtenv can discover the root automatically
- Check the wrapped error (%v) from vtenv.VtRoot() for the specific reason the root lookup failed
Example fix
// before: hook.ExecuteContext(...) fails with 'cannot get VTROOT'
// after (in deployment env)
export VTROOT=/usr/local/vitess
// or in Go tests
os.Setenv("VTROOT", "/usr/local/vitess") Defensive patterns
Strategy: validation
Validate before calling
if os.Getenv("VTROOT") == "" {
if _, err := vtenv.VtRoot(); err != nil {
return fmt.Errorf("hooks unavailable: VTROOT not resolvable: %v", err)
}
} Try / catch
hr := hook.ExecuteOptional(h)
if hr.ExitStatus == hook.HOOK_VTROOT_ERROR {
log.Warningf("hooks disabled: VTROOT not set")
return nil
} Prevention
- Always set VTROOT in deployment environments and container images
- Check exit status HOOK_VTROOT_ERROR to degrade gracefully when hooks are unavailable
- Verify the Vitess distribution layout (vthook dir under root) before enabling hooks
When it happens
Trigger: Calling hook.ExecuteContext / ExecuteAsWritePipe / ExecuteAsReadPipe (via findHook) in a process where the VTROOT-resolving logic fails — vtenv.VtRoot() returns an error because no Vitess root is configured/discoverable.
Common situations: Running Vitess binaries outside a standard deployment layout; VTROOT env var unset and binary not run from within a Vitess distribution; container images missing the vtenv-discoverable root.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- --s3-backup-storage-bucket required
- direct DDL is disabled
- online DDL is disabled
- --batch-size requires 'direct' ddl_strategy
- --batch-size conflicts with --uuid-list. Batching does not s
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/3a509eefb14dc29d.
Report an issue: GitHub.