k3s-io/k3s · critical

failed to migrate content from sqlite to etcd: %w

Error message

failed to migrate content from sqlite to etcd: %w

What it means

When embedded etcd is initialized without reset (i.e. `--cluster-init` on a node whose SQLite datastore file exists), newCluster bootstraps a fresh etcd cluster and then migrateFromSQLite copies the existing SQLite data through kine into etcd. This wrapping error means that migration failed; the underlying cause is in the %w chain. This is the standalone-SQLite-to-HA-etcd upgrade path.

Source

Thrown at pkg/etcd/etcd.go:911

	return ip, nil
}

// newCluster calls cluster to start up etcd for a new cluster, with no existing members.
// Existing data from sqlite is migrated over, if present.
func (e *ETCD) newCluster(ctx context.Context, wg *sync.WaitGroup, reset bool) error {
	logrus.Infof("Starting etcd for new cluster, cluster-reset=%v", reset)
	err := e.cluster(ctx, wg, reset, executor.InitialOptions{
		AdvertisePeerURL: e.peerURL(),
		Cluster:          fmt.Sprintf("%s=%s", e.name, e.peerURL()),
		State:            "new",
	})
	if err != nil {
		return err
	}
	if !reset {
		if err := e.migrateFromSQLite(ctx); err != nil {
			return fmt.Errorf("failed to migrate content from sqlite to etcd: %w", err)
		}
	}
	return nil
}

func (e *ETCD) migrateFromSQLite(ctx context.Context) error {
	_, err := os.Stat(sqliteFile(e.config))
	if os.IsNotExist(err) {
		return nil
	} else if err != nil {
		return err
	}

	logrus.Infof("Migrating content from sqlite to etcd")

	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

View on GitHub (pinned to 6ba341e396)

Solutions

  1. Read the wrapped cause in the log line (the %w suffix) - it distinguishes SQLite corruption from etcd/kine connectivity issues.
  2. Back up the whole data dir, then restore from an etcd snapshot instead of migrating: `k3s server --cluster-reset --cluster-reset-restore-path=<snapshot.db>` after starting --cluster-init once.
  3. Verify the SQLite db is healthy before retrying: `sqlite3 /var/lib/rancher/k3s/server/db/state.db 'PRAGMA integrity_check;'` - if corrupt, restore from backup or snapshot rather than retrying migration.
  4. Ensure you only run --cluster-init once per node and that all servers converge on the same initial cluster.

Example fix

# before (migration fails or db is suspect)
k3s server --cluster-init

# after (clean HA bootstrap from a good snapshot)
k3s server --cluster-init                      # first start: create empty etcd cluster
k3s server --cluster-reset \
  --cluster-reset-restore-path=/backups/etcd-snapshot.db   # restore data into it
Defensive patterns

Strategy: try-catch

Validate before calling

// Before enabling --cluster-init on an existing node, sanity-check the SQLite db:
if _, err := os.Stat(filepath.Join(dataDir, "server", "db", "state.db")); err == nil {
    out, err := exec.Command("sqlite3", filepath.Join(dataDir, "server", "db", "state.db"), "PRAGMA integrity_check;").CombinedOutput()
    if err != nil || strings.TrimSpace(string(out)) != "ok" {
        log.Fatalf("state.db not healthy - restore from snapshot instead of migrating: %v %s", err, out)
    }
}

Try / catch

// Wrap and inspect the migration error chain; fall back to snapshot restore on corruption:
if err := server.Start(ctx); err != nil {
    var migErr *fmt.WrapError // illustrative: check message prefix instead
    if strings.Contains(err.Error(), "failed to migrate content from sqlite to etcd") {
        log.Fatal("migration failed - preserve data dir, then restore from an etcd snapshot with --cluster-reset-restore-path")
    }
    log.Fatal(err)
}

Prevention

When it happens

Trigger: Running `k3s server --cluster-init` on a node with an existing <data-dir>/server/db/state.db (pkg/etcd/etcd.go:902-912). Migration fails if the SQLite db is corrupt/unreadable, kine cannot open it, etcd rejects the writes, or a previous half-completed migration left inconsistent state.

Common situations: Converting a single-node SQLite k3s to embedded-etcd HA; retrying --cluster-init after a first failed attempt; very old k3s versions with schema drift; state.db damaged by an unclean shutdown.

Related errors


AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15). Data as JSON: /api/errors/9c56f0c091e737a8. Report an issue: GitHub.