gravitational/teleport · warning

version check failed

Error message

version check failed

What it means

ErrVersionCheck is returned when a downloaded or installed tool binary cannot be executed to determine its version — running the tool to print its version failed or produced unusable output. The updater uses this to treat the installed tools directory as broken and fall back to the local version rather than re-execing into a possibly corrupt binary.

Source

Thrown at lib/autoupdate/tools/utils.go:53

	"github.com/coreos/go-semver/semver"
	"github.com/gravitational/trace"

	"github.com/gravitational/teleport/api/constants"
	"github.com/gravitational/teleport/api/types"
	"github.com/gravitational/teleport/lib/automaticupgrades/version"
	"github.com/gravitational/teleport/lib/autoupdate"
	"github.com/gravitational/teleport/lib/modules"
	"github.com/gravitational/teleport/lib/utils"
	"github.com/gravitational/teleport/lib/utils/packaging"
)

var (
	// ErrNoBaseURL is returned when `TELEPORT_CDN_BASE_URL` must be set
	// in order to proceed with managed updates.
	ErrNoBaseURL = errors.New("baseURL is not defined")
	// ErrVersionCheck is returned when the downloaded version fails
	// to execute for version identification.
	ErrVersionCheck = errors.New("version check failed")
)

// Dir returns the client tools installation directory path, using the following fallback order:
// $TELEPORT_TOOLS_DIR, $TELEPORT_HOME/bin, and $HOME/.tsh/bin.
func Dir() (string, error) {
	toolsDir := os.Getenv(teleportToolsDirsEnv)
	if toolsDir == "" {
		toolsDir = os.Getenv(types.HomeEnvVar)
		if toolsDir == "" {
			var err error
			toolsDir, err = os.UserHomeDir()
			if err != nil {
				return "", trace.Wrap(err)
			}
			toolsDir = filepath.Join(toolsDir, ".tsh", "bin")
		} else {
			toolsDir = filepath.Join(toolsDir, "bin")
		}

View on GitHub (pinned to 1283425b60)

Solutions

  1. Delete the affected binary (or the whole tools directory, e.g. ~/.tsh/bin) so the updater re-downloads a fresh copy.
  2. Run the tool manually to see the underlying exec failure (`~/.tsh/bin/tsh version`) — missing libs or arch mismatch will show there.
  3. Retry the update; the updater skips the broken version and keeps executing the local one.
  4. Check disk space and download integrity if corruption recurs.

Example fix

// before
toolsVersion, err := CheckExecutedToolVersion(u.toolsDir)
if err != nil {
    return trace.Wrap(err) // hard failure on broken binary
}
// after
if trace.IsNotFound(err) || errors.Is(err, ErrVersionCheck) {
    return &UpdateResponse{Version: u.localVersion, ReExec: false}, nil, nil // fall back to local
}
Defensive patterns

Strategy: fallback

Validate before calling

out, err := exec.Command(toolPath, "version").CombinedOutput()
if err != nil {
    // tool binary broken; purge it before updating
    _ = os.Remove(toolPath)
}

Type guard

func IsVersionCheckFailed(err error) bool { return errors.Is(err, tools.ErrVersionCheck) }

Try / catch

toolsVersion, err := CheckExecutedToolVersion(u.toolsDir)
if trace.IsNotFound(err) || errors.Is(err, ErrVersionCheck) {
    return &UpdateResponse{Version: u.localVersion, ReExec: false}, nil, nil
}

Prevention

When it happens

Trigger: utils.go:123 — executing the tool to identify its version fails or emits unparseable output, so CheckExecutedToolVersion/CheckLocal returns ErrVersionCheck; updater.go:203 — Update() sees this error and returns the local version with ReExec:false instead of switching binaries.

Common situations: A truncated or corrupted download in the tools directory; a binary with a broken dynamic-linker dependency (missing shared libraries) that exits nonzero; a stale/incompatible binary from a different architecture.

Related errors


AI-assisted analysis of gravitational/teleport@1283425b60 (2026-09-02). Data as JSON: /api/errors/2fa7fef41de2be58. Report an issue: GitHub.