vitessio/vitess · error · ErrMySQLShellPreCheck

%w: "skipBinlog" needs to set to true

Error message

%w: "skipBinlog" needs to set to true

What it means

restorePreCheck requires mysql-shell's load dump utility to run with skipBinlog=true. During a Vitess restore, replication recovery is driven by the restored GTID position and applying the load through the binary log would be wrong and slow. The check rejects any loadFlags where "skipBinlog" is missing or not the boolean true.

Source

Thrown at go/vt/mysqlctl/mysqlshellbackupengine.go:519

		return shouldDeleteUsers, fmt.Errorf("%w: at least the --js flag is required in the value of the flag --mysql-shell-flags", ErrMySQLShellPreCheck)
	}

	loadFlags := map[string]any{}
	err = json.Unmarshal([]byte(mysqlShellLoadFlags), &loadFlags)
	if err != nil {
		return false, fmt.Errorf("%w: unable to parse JSON of load flags", ErrMySQLShellPreCheck)
	}

	if val, ok := loadFlags["updateGtidSet"]; !ok || val != "replace" {
		return false, fmt.Errorf("%w: mysql-shell needs to restore with updateGtidSet set to \"replace\" to work with Vitess", ErrMySQLShellPreCheck)
	}

	if val, ok := loadFlags["progressFile"]; !ok || val != "" {
		return false, fmt.Errorf("%w: \"progressFile\" needs to be empty as vitess always starts a restore from scratch", ErrMySQLShellPreCheck)
	}

	if val, ok := loadFlags["skipBinlog"]; !ok || val != true {
		return false, fmt.Errorf("%w: \"skipBinlog\" needs to set to true", ErrMySQLShellPreCheck)
	}

	if val, ok := loadFlags["loadUsers"]; ok && val == true {
		shouldDeleteUsers = true
	}

	if mysqlShellSpeedUpRestore {
		version, err := params.Mysqld.GetVersionString(ctx)
		if err != nil {
			return false, fmt.Errorf("%w: failed to fetch MySQL version: %v", ErrMySQLShellPreCheck, err)
		}

		_, sv, err := ParseVersionString(version)
		if err != nil {
			return false, fmt.Errorf("%w: failed to parse MySQL version (version: %s): %v", ErrMySQLShellPreCheck, version, err)
		}

		versionStr := fmt.Sprintf("%d.%d.%d", sv.Major, sv.Minor, sv.Patch)

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Set "skipBinlog" to boolean true in the loadFlags map of the mysql-shell backupengine config
  2. Ensure it is a real boolean, not the string "true" (YAML unquoted, JSON without quotes)
  3. Re-check the sibling required flags: updateGtidSet=replace and progressFile empty

Example fix

// before
"loadFlags": {"updateGtidSet": "replace", "skipBinlog": "true"}
// after
"loadFlags": {"updateGtidSet": "replace", "skipBinlog": true}
Defensive patterns

Strategy: validation

Validate before calling

if v, ok := loadFlags["skipBinlog"]; !ok || v != true {
    return fmt.Errorf("mysql-shell loadFlags.skipBinlog must be boolean true")
}

Try / catch

if _, err := engine.ExecuteRestore(ctx, params, backupDir); err != nil {
    if errors.Is(err, mysqlctl.ErrMySQLShellPreCheck) {
        // inspect and correct loadFlags before re-running restore
    }
}

Prevention

When it happens

Trigger: ExecuteRestore -> restorePreCheck when loadFlags["skipBinlog"] is absent, set to false, or set to a non-boolean value (e.g. string "true"), which fails the `!= true` comparison.

Common situations: Operators add skipBinlog as a YAML/JSON string "true" instead of boolean true; the flag is simply omitted from a hand-written loadFlags block; a config translated from a mysql-shell CLI example omits the flag because it isn't a CLI flag on their shell version.

Related errors


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