bytebase/bytebase · error

expecting variable %s, but got %s

Error message

expecting variable %s, but got %s

What it means

In getServerVariable, after querying @@variable_name, the code verifies the returned Variable_name column matches the requested name. This error fires when the server echoes back a different variable name than the one asked for — meaning the variable does not exist (server returned an unexpected/empty mapping) or the result row is misaligned. It is an invariant check on server variables during SyncInstance.

Source

Thrown at backend/plugin/db/mysql/sync.go:153

		Metadata: &storepb.Instance{
			MysqlLowerCaseTableNames: lowerCaseTableNames,
			Roles:                    instanceRoles,
		},
	}, nil
}

func (d *Driver) getServerVariable(ctx context.Context, varName string) (string, error) {
	db := d.GetDB()
	query := fmt.Sprintf("SHOW VARIABLES LIKE '%s'", varName)
	var varNameFound, value string
	if err := db.QueryRowContext(ctx, query).Scan(&varNameFound, &value); err != nil {
		if err == sql.ErrNoRows {
			return "", common.FormatDBErrorEmptyRowWithQuery(query)
		}
		return "", util.FormatErrorWithQuery(err, query)
	}
	if varName != varNameFound {
		return "", errors.Errorf("expecting variable %s, but got %s", varName, varNameFound)
	}
	return value, nil
}

func containsInvisibleChars(data []byte) bool {
	// Iterate over the byte slice as runes
	for len(data) > 0 {
		r, size := utf8.DecodeRune(data)
		if r == utf8.RuneError && size == 1 {
			// If the byte slice contains invalid UTF-8 characters, treat it as invisible
			return true
		}
		// Check if the rune is not printable
		if !unicode.IsPrint(r) {
			return true
		}
		// Move to the next rune
		data = data[size:]

View on GitHub (pinned to 1870550677)

Solutions

  1. Run SELECT @@<variable> manually on the server to confirm the variable exists
  2. Check the server dialect/version; use a dialect-appropriate variable or skip it when absent
  3. Verify the variable name string passed into getServerVariable matches the SQL query construction exactly
  4. Add version-aware variable lookup so unsupported variables are skipped instead of erroring

Example fix

// before
if varName != varNameFound {
    return "", errors.Errorf("expecting variable %s, but got %s", varName, varNameFound)
}
// after
if varNameFound == "" {
    return "", nil // variable not supported by this server; use default
}
if varName != varNameFound {
    return "", errors.Errorf("expecting variable %s, but got %s", varName, varNameFound)
}
Defensive patterns

Strategy: validation

Validate before calling

var supported bool
db.QueryRow("SELECT COUNT(*) FROM information_schema.variables_info WHERE variable_name = ?", varName).Scan(&supported)
// if !supported, skip the variable or use a default instead of erroring

Try / catch

value, err := getServerVariable(ctx, db, "version_comment")
if err != nil && strings.Contains(err.Error(), "expecting variable") {
    value = "" // treat unsupported variable as default
}

Prevention

When it happens

Trigger: Requesting a server variable (e.g. version_comment, max_connections) that the connected MySQL-compatible server (MariaDB, OceanBase, TiDB) does not define, so the result set returns a different name or the code's expectation no longer matches the dialect.

Common situations: Syncing a MariaDB/OceanBase/TiDB instance whose variable set differs from vanilla MySQL; MySQL version changes renaming/removing variables; typos in the variable name passed to getServerVariable.

Related errors


AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06). Data as JSON: /api/errors/ecba51fe57c382d6. Report an issue: GitHub.