Stalwart-migrate 1.0.0: Registry deserialization errors during v0.16.27 upgrade

Issue Description

I’m reporting an issue encountered while upgrading my Stalwart server from v0.16.27 to v1.0.0.

Environment:

  • OS: Linux (systemd installation)
  • Source version: Stalwart 0.16.27
  • Migration tool: stalwart-migrate 1.0.0
  • Database: RocksDB
  • Blob storage: Local RocksDB
  • Migration performed offline, with the original server stopped

Issue:

The stalwart-migrate prepare command failed with a registry.deserialization-error, preventing the migration from proceeding.

My Stalwart 0.16.27 installation had been functioning normally before the upgrade.

I compiled a modified version of the migration tool with additional diagnostic logging and scanned the registry.

The scan identified 21 unreadable entries out of 2,870, including:

  • Log
  • MtaDeliverySchedule
  • MtaExtensions
  • MtaHook
  • MtaOutboundStrategy
  • MtaStageAuth
  • MtaStageConnect
  • OidcProvider
  • ReportSettings
  • WebHook

I confirmed that the registry deserialization source files bundled with the migrator match those from Stalwart v0.16.27.

Workaround:

I modified crates/source-v016/src/adapter/registry.rs to skip entries that fail deserialization rather than aborting the migration.

With this modification, the migration completed successfully:

  • 3,630 emails migrated
  • 1 account migrated
  • 2,698 blobs copied
  • Full verification: 0 mismatches, 0 unexplained differences

The skipped registry entries were not migrated, so some configuration settings may still need manual restoration.

Suggestion:

It would be useful if stalwart-migrate could handle unreadable legacy registry entries more gracefully, for example by allowing users to skip them with an explicit warning instead of aborting the entire migration.

Expected Behavior

stalwart-migrate prepare should successfully read and convert the registry from Stalwart 0.16.27 to 1.0.

If a legacy registry entry cannot be deserialized, the migration tool should report its type and ID and ideally allow skipping it with a warning

Actual Behavior

stalwart-migrate 1.0.0 fails during prepare with registry.deserialization-error.

I identified 21 unreadable registry entries out of 2,870, including Log, MtaDeliverySchedule, MtaHook, MtaExtensions, MtaOutboundStrategy, OidcProvider and others.

I modified crates/source-v016/src/adapter/registry.rs to skip unreadable entries.

After this modification, the migration completed successfully:

  • 3,630 emails migrated
  • 1 account migrated
  • Full verification: 0 mismatches

One security concern: the original error message includes the complete Base64-encoded registry value, which in my case contained a PEM private key.

Reproduction Steps

  1. Install Stalwart 0.16.27 with RocksDB on Linux.
  2. Install stalwart-migrate 1.0.0.
  3. Execute:
    stalwart-migrate prepare --source /etc/stalwart/config.json --state /var/lib/stalwart-migrate
    
  4. Observe registry.deserialization-error.
  5. The same issue occurs with an offline copy of the RocksDB database.
  6. Patching the registry iterator to skip entries that fail deserialization allows the migration to complete.

The issue depends on the stored registry entries, so it may not reproduce on a fresh installation.

Relevant Log Output

ERROR stalwart_migrate: command failed
error=account error: Registry deserialization error
(registry.deserialization-error)
causedBy = vendor/v016/crates/store/src/registry/mod.rs:96
value = [REDACTED: contains PEM private key]

Diagnostic:
REGISTRY DECODE FAILED: type=Log, id=20080258862541
REGISTRY DECODE FAILED: type=MtaDeliverySchedule, id=20080258862541

Registry scan:
21 errors, 2870 entries checked

After applying the skip patch:
run finished status=ok
verify: 1 accounts checked, 0 mismatches, 0 unexplained (ok)

Stalwart Version

v1.x

Installation Method

Binary (Linux)

Database Backend

RocksDB

Blob Storage

RocksDB

Search Engine

Internal

Directory Backend

Internal

I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.

on

I have searched this support forum (open and closed topics) and confirm this is not a duplicate.

on

The docs don’t describe a way to skip unreadable 0.16 registry entries, and they don’t mention this error.

Thanks for the detailed report. The docs don’t cover this failure, and I couldn’t find anything about how stalwart-migrate is meant to handle registry entries that fail to deserialize.

What I could confirm:

  • registry.deserialization-error is documented as “A registry entry could not be deserialized; it may have been written by an incompatible version of the server” (events reference).
  • The upgrade guide describes prepare as reading the 0.16 settings and converting them to 1.0. It doesn’t mention skipping unreadable entries, and it gives no recovery path for this error (upgrade guide).

Your skip patch moved the migration forward, but the 21 skipped entries (Log, MtaHook, OidcProvider, WebHook and so on) were not converted. Compare your 0.16 settings with the 1.0 server after the migration and recreate anything missing by hand.

The error message including the full Base64 registry value, which here contained a PEM private key, is worth flagging. Treat any logs or terminal output from the failed runs as sensitive, and consider rotating that key.

This isn’t covered in the current docs. A community member or staff member will follow up.

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong.

This has been fixed. Please try again with stalwart-migrate 1.0.1 which is being compiled now.