vitessio/vitess · error

unable to perform time_zone conversions from

Error message

unable to perform time_zone conversions from %s to UTC — result of the attempt was: %s. Either the specified source time zone is invalid or the time zone tables have not been loaded on the %s tablet

What it means

When the MaterializeSettings specifies a source time zone (tz conversion), the materializer validates that MySQL can convert a test datetime from that zone to UTC by executing a query on the target primary. If the result cannot be parsed back as a datetime, either the time zone name is invalid on the server or the MySQL time zone tables are not loaded on that tablet.

Solutions

  1. Load time zone tables on the tablet's MySQL: run `mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql`
  2. Verify with `SELECT CONVERT_TZ('2023-01-01 12:00:00','UTC','<your-tz>');` returning non-NULL
  3. Fix the time zone name typo in the workflow settings (must be a valid IANA name like 'America/New_York')
  4. Restart the workflow after fixing the tablet environment

Example fix

// before (on tablet host)
# mysql time zone tables missing
// after
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql
# then verify
mysql -e "SELECT CONVERT_TZ('2023-01-01 12:00:00','UTC','America/New_York');"
Defensive patterns

Strategy: validation

Validate before calling

qr, err := conn.ExecuteFetch("SELECT CONVERT_TZ('2023-01-01 12:00:00','UTC','"+tz+"')", 1, false)
if err != nil || qr.Rows[0][0].IsNull() || qr.Rows[0][0].ToString() == "NULL" {
    return fmt.Errorf("time zone %s unusable on tablet: load tz tables via mysql_tzinfo_to_sql", tz)
}

Try / catch

if err := workflow.Start(ctx); err != nil {
    if strings.Contains(err.Error(), "unable to perform time_zone conversions") {
        log.Error("Load tz tables: mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql", slog.Any("error", err))
    }
}

Prevention

When it happens

Trigger: MaterializeSettings with a SourceTimeZone (or related tz config) where the target primary tablet's mysqld lacks time zone tables (`SELECT CONVERT_TZ(...)` returns NULL) or the tz string is misspelled/unknown (e.g. 'America/New_Yorlk').

Common situations: MySQL installed without the mysql.time_zone* tables populated (mysql_tzinfo_to_sql not run); custom container images missing /usr/share/zoneinfo; typo in the IANA time zone name in workflow config.

Related errors


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

Appendix: source

Thrown at go/vt/wrangler/materializer.go:1575

// gets elected: in this case user will either see errors during vreplication or vdiff will report mismatches.
func (mz *materializer) checkTZConversion(ctx context.Context, tz string) error {
	err := mz.forAllTargets(func(target *topo.ShardInfo) error {
		targetPrimary, err := mz.wr.ts.GetTablet(ctx, target.PrimaryAlias)
		if err != nil {
			return vterrors.Wrapf(err, "GetTablet(%v) failed", target.PrimaryAlias)
		}
		testDateTime := "2006-01-02 15:04:05"
		query := fmt.Sprintf("select convert_tz(%s, %s, 'UTC')", encodeString(testDateTime), encodeString(tz))
		qrproto, err := mz.wr.tmc.ExecuteFetchAsApp(ctx, targetPrimary.Tablet, false, &tabletmanagerdatapb.ExecuteFetchAsAppRequest{
			Query:   []byte(query),
			MaxRows: 1,
		})
		if err != nil {
			return vterrors.Wrapf(err, "ExecuteFetchAsApp(%v, %s)", targetPrimary.Tablet, query)
		}
		qr := sqltypes.Proto3ToResult(qrproto)
		if gotDate, err := time.Parse(testDateTime, qr.Rows[0][0].ToString()); err != nil {
			return fmt.Errorf("unable to perform time_zone conversions from %s to UTC — result of the attempt was: %s. Either the specified source time zone is invalid or the time zone tables have not been loaded on the %s tablet",
				tz, gotDate, targetPrimary.Alias)
		}
		return nil
	})
	return err
}

// filterSourceShards filters out source shards that do not overlap with the
// provided target shard. This is an optimization to avoid copying unnecessary
// data between the shards. This optimization is only applied for MoveTables
// when the source and target shard have the same primary vindexes.
func (mz *materializer) filterSourceShards(targetShard *topo.ShardInfo) []*topo.ShardInfo {
	if mz.primaryVindexesDiffer || mz.ms.MaterializationIntent != vtctldatapb.MaterializationIntent_MOVETABLES {
		// Use all source shards.
		return mz.sourceShards
	}
	// Use intersecting source shards.
	var filteredSourceShards []*topo.ShardInfo

View on GitHub (pinned to 01a25a7d17)