Vault Error: 'error migrating data' Storage Migration or Upgrade Failure on Start
Fix Vault storage migration and upgrade failures: seal before migrating, write a correct migrate.hcl, clear or resume the migration lock, match seal types, and roll upgrades safely.
- #vault
- #secrets
- #security-hardening
- #troubleshooting
- #errors
Stuck on this HashiCorp Vault error? Get the free incident triage checklist
A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.
Exact Error Message
$ vault operator migrate -config=migrate.hcl
2026-07-19T09:14:02.771Z [INFO] copying keys from source to destination
Error migrating: error migrating data: failed to write value to destination:
failed to persist storage entry: context deadline exceeded
On a node that starts against partially migrated or newer storage you may instead see:
Error initializing core: migration is in progress; please complete the migration
before starting Vault, or run 'vault operator migrate' with -start to resume
Error parsing Seal configuration: seal type 'shamir' does not match
seal type stored in the destination backend
What It Means
Vault’s storage backend holds every encrypted secret, lease, token, and policy. vault operator migrate performs an offline copy of that data from one backend to another — typically Consul or a filesystem backend into integrated Raft storage. It is a bulk key-by-key copy, not a live replication mechanism, and it requires exclusive ownership of both backends. To enforce that, Vault writes a migration marker into storage. Any Vault process that finds an incomplete marker refuses to start rather than serving from half-copied data.
Upgrade failures come from a related but distinct constraint: Vault’s storage schema is forward-only. Each release may upgrade on-disk structures during the first unseal, and there is no downgrade path — an older binary pointed at storage a newer binary has touched will fail to initialise its core. Combined with the requirement that HA clusters upgrade standbys before the active node, this makes upgrade order load-bearing. The seal type mismatch in the second message above is the third common trap: the destination backend records which seal protects the master key, so migrating from a Shamir-sealed source into a backend that already carries auto-unseal metadata (or the reverse) aborts before any data moves.
Common Causes
- Vault was still running and unsealed when
vault operator migratewas invoked, so the source kept changing under the copy. - A previous migration was interrupted, leaving the migration lock in place and blocking both start and re-run.
- The
migrate.hclstanzas are wrong — a mistypedpath, a missingnode_id, or credentials that only work for one of the two backends. - The upgrade skipped intermediate versions instead of stepping through them and reading each upgrade guide.
- The active node was upgraded before the standbys, so older peers could not follow the newer leader.
- The destination backend records a different seal type than the running configuration declares.
Diagnostic Commands
Confirm nothing is still serving. Every Vault process must be stopped, or at minimum sealed, before a migration runs:
systemctl status vault
vault status | grep -E 'Sealed|HA Mode|Storage Type'
Validate the migration config before you trust it with production data. A parse error at this stage is far cheaper than one halfway through the copy:
cat migrate.hcl
vault operator migrate -config=migrate.hcl -dryrun
Inspect the source backend directly to confirm the data is where you think it is. For a Raft source, the node data directory should contain raft.db and a vault subdirectory:
ls -la /opt/vault/data
ls -la /opt/vault/data/raft
du -sh /opt/vault/data
Check that the destination has room and that the Vault user can write to it — context deadline exceeded on write is very often a disk, permissions, or network problem rather than a Vault one:
df -h /opt/vault/data-new
sudo -u vault touch /opt/vault/data-new/.probe && echo writable
Take a snapshot before you do anything else. If the cluster is currently healthy and unsealed, this is your rollback:
vault operator raft snapshot save /backup/vault-pre-upgrade.snap
ls -lh /backup/vault-pre-upgrade.snap
If the snapshot itself fails, resolve that first — see Vault error: Raft snapshot failed.
Finally, read the startup logs in full. The line above the failure usually names the exact key that could not be written:
journalctl -u vault --since "30 min ago" --no-pager | grep -iE "migrat|seal|storage|panic"
Step-by-Step Resolution
- Stop Vault everywhere and confirm it stays stopped. Migration against a live backend produces silent data loss, not an error:
sudo systemctl stop vault
pgrep -a vault || echo "no vault processes running"
- Write a correct
migrate.hclwith exactly onestorage_sourceand onestorage_destinationstanza. The stanza labels are the backend types, and both must be fully configured:
storage_source "consul" {
address = "127.0.0.1:8500"
path = "vault/"
}
storage_destination "raft" {
path = "/opt/vault/data"
node_id = "vault-0"
}
cluster_addr = "https://vault-0.example.com:8201"
- Run the migration and let it finish. On a large backend this can take a long time; run it under
tmuxornohupso a dropped SSH session does not interrupt it:
sudo -u vault vault operator migrate -config=migrate.hcl 2>&1 | tee /var/log/vault-migrate.log
- If a previous attempt was interrupted, resume rather than restarting from scratch. The
-startflag tells the migration to begin at a given key prefix, skipping what was already copied:
sudo -u vault vault operator migrate -config=migrate.hcl -start "logical/"
Only start over from the beginning against a freshly emptied destination — a partial copy layered under a full re-run leaves stale keys behind.
- Reconcile the seal type. The destination records the seal that protects the master key, so your
vault.hclmust declare the same seal the data was encrypted under. Migrating between seal types is a separate operation from migrating storage:
storage "raft" {
path = "/opt/vault/data"
node_id = "vault-0"
}
seal "awskms" {
region = "us-east-1"
kms_key_id = "alias/vault-unseal"
}
listener "tcp" {
address = "0.0.0.0:8200"
tls_cert_file = "/etc/vault/tls/vault.crt"
tls_key_file = "/etc/vault/tls/vault.key"
}
If the new node cannot reach that KMS key, the failure surfaces as an unseal error instead — see Vault error: auto-unseal KMS access denied.
- For version upgrades on an HA cluster, upgrade standbys first, then step down the active node last. Never upgrade the active node while standbys are on the older binary:
# on each standby, one at a time
sudo systemctl stop vault
sudo dnf upgrade -y vault
sudo systemctl start vault
vault status | grep -E 'HA Mode|Version'
# only once every standby is healthy on the new version
vault operator step-down # run against the current active node
sudo systemctl stop vault && sudo dnf upgrade -y vault && sudo systemctl start vault
Upgrade one minor version at a time and read the upgrade guide for each intermediate release — some releases carry storage or plugin changes that must be applied in sequence. Automated rolling upgrades driven by autopilot (Vault Enterprise) handle this ordering for you, but the same version-by-version rule applies.
- Verify before declaring success. Unseal, confirm the storage type, and read a known secret end to end:
vault status | grep -E 'Sealed|Storage Type|Version'
vault operator raft list-peers
vault kv get secret/app/prod/db
Prevention
- Always take and verify a snapshot immediately before any migration or upgrade, and confirm it restores in a test cluster.
- Rehearse the migration against a copy of production data so the runtime and failure modes are known in advance.
- Upgrade one minor version at a time and read each release’s upgrade guide rather than jumping several versions.
- Keep
migrate.hclin version control next to yourvault.hclso the source and destination stanzas are reviewable. - Never plan to downgrade — the storage schema is forward-only, so a rollback means restoring a snapshot to the old version.
- Pin the Vault package version in configuration management so an unattended
dnf upgradecannot upgrade the active node first.
Related Errors
migration is in progress; please complete the migration before starting Vault— the migration lock is still set; resume or complete it.failed to setup raft storage: node_id is required— the destination Raft stanza is incomplete.Error initializing storage of type consul: dial tcp: connection refused— the source backend is unreachable, so nothing was copied.failed to decrypt encrypted stored keys— the seal declared in config does not match the one the destination data was sealed with.
Frequently Asked Questions
Can I migrate while Vault is running? No. vault operator migrate requires exclusive access to both backends and copies data key by key; anything written to the source during the copy is silently lost. Stop every Vault process on every node first and confirm with pgrep.
How do I resume an interrupted migration? Re-run the same command with -start set to the key prefix where the log stopped. This skips already-copied keys instead of restarting a multi-hour copy. Only wipe the destination and start over if you are unsure what was written.
Can I downgrade if the new version misbehaves? Not by swapping the binary. Vault’s storage schema is forward-only, so an older binary will refuse to initialise against storage a newer one has upgraded. Rollback means restoring the pre-upgrade snapshot into a cluster running the old version.
Which node do I upgrade first in an HA cluster? Standbys first, one at a time, then vault operator step-down on the active node and upgrade it last. Autopilot automated upgrades (Vault Enterprise) orchestrate this for you. For more Vault operations fixes, see the Vault guides.
Fixed it? Get 500 HashiCorp Vault & DevOps AI prompts — free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.
Did this fix your issue?
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.