vitessio/vitess · error · errUnsupportedCompressionEngine

%w %q

Error message

%w %q

What it means

During XtraBackup restore, extractFiles validates the requested backup's compression engine. If the backup manifest indicates a non-compressed backup (no compression engine) but the external compressor engine is selected, it fails with errUnsupportedCompressionEngine wrapped with the engine name, since there is nothing for an external decompressor to decompress.

Source

Thrown at go/vt/mysqlctl/xtrabackupengine.go:743

		if compressed {
			var decompressor io.ReadCloser
			deCompressionEngine := bm.CompressionEngine
			if deCompressionEngine == "" {
				// For backward compatibility. Incase if Manifest is from N-1 binary
				// then we assign the default value of compressionEngine.
				deCompressionEngine = PgzipCompressor
			}
			externalDecompressorCmd := resolveExternalDecompressor(bm.ExternalDecompressor)
			if externalDecompressorCmd != "" {
				if deCompressionEngine == ExternalCompressor {
					deCompressionEngine = externalDecompressorCmd
					decompressor, err = newExternalDecompressor(ctx, deCompressionEngine, reader, logger)
				} else {
					decompressor, err = newBuiltinDecompressor(deCompressionEngine, reader, logger)
				}
			} else {
				if deCompressionEngine == ExternalCompressor {
					return fmt.Errorf("%w %q", errUnsupportedCompressionEngine, ExternalCompressor)
				}
				decompressor, err = newBuiltinDecompressor(deCompressionEngine, reader, logger)
			}
			if err != nil {
				return vterrors.Wrap(err, "can't create decompressor")
			}
			srcDecompressors = append(srcDecompressors, ioutil.NewTimeoutCloser(ctx, decompressor, closeTimeout))
			reader = decompressor
		}

		srcReaders = append(srcReaders, reader)
	}
	defer func() {
		for _, decompressor := range srcDecompressors {
			if cerr := decompressor.Close(); cerr != nil {
				logger.Errorf("failed to close decompressor: %v", cerr)
			}
		}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Remove the external-compressor setting from the restore configuration so the builtin path (or no decompression) is used.
  2. Take a new backup with the intended compression engine, then restore from it.
  3. Pick a backup manifest whose compression engine matches the configured restore engine.
  4. Verify the compression flags on the tablet (e.g. backup_engine_implementation/compression settings) match how the backup was actually taken.

Example fix

// before: restore config forces external compressor on uncompressed backup
restoring with ExternalCompressor -> errUnsupportedCompressionEngine
// after: align engine with backup
// unset external compression or take backup with --compression-engine=external
Defensive patterns

Strategy: validation

Validate before calling

if manifest.CompressionEngineName == "" && restoreConfig.CompressionEngine == "external" {
  return errors.New("backup is uncompressed; remove external compressor setting")
}

Type guard

func backupIsCompressed(m *backupstorage.BackupManifest) bool { return m.CompressionEngineName != "" }

Try / catch

if err := restore(ctx); err != nil {
  if errors.Is(err, mysqlctl.ErrUnsupportedCompressionEngine) {
    log.Warn("fallback: retry restore without external compression")
  }
}

Prevention

When it happens

Trigger: Restoring from a backup whose BackupManifest has no CompressionEngineName while the tablet's restore configuration specifies the external compressor engine (restore_from_backup with ExternalCompressor).

Common situations: Backup was taken without compression but tablet flags/config changed to expect external compression; operator switched --compression-engine / restore flags between backup generations; mixed-version clusters where older backups were uncompressed.

Related errors


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