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

  1. Set the VTROOT environment variable to the Vitess installation root before starting the process
  2. Run the binary from within a proper Vitess distribution so vtenv can discover the root automatically
  3. 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

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


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