k3s-io/k3s · critical

no bootstrap data is available to reconcile against

Error message

no bootstrap data is available to reconcile against

What it means

Emitted at the end of the reconcile bootstrap path when 'buf' is still nil: neither the HTTP-join branch (fetching bootstrap from an existing server) nor the managed-datastore branch (decrypting the '/bootstrap' key) produced a bootstrap payload. It means the server has no source of truth for its control-plane state and cannot continue.

Source

Thrown at pkg/cluster/bootstrap.go:338

		kv, c.saveBootstrap, err = getBootstrapKeyFromStorage(ctx, storageClient, normalizedToken, token)
		if err != nil {
			return err
		}
		if kv == nil || len(kv.Value) == 0 {
			return errors.New("no bootstrap data found in datastore - check server token value and verify datastore integrity")
		}

		dbRawData, err := decrypt(normalizedToken, kv.Value)
		if err != nil {
			return err
		}

		buf = bytes.NewReader(dbRawData)
	}

	if buf == nil {
		return errors.New("no bootstrap data is available to reconcile against")
	}

	paths, err := bootstrap.ObjToMap(crb)
	if err != nil {
		return err
	}

	files := make(bootstrap.PathsDataformat)
	if !isMigrated(buf, &files) {
		if err := migrateBootstrapData(ctx, buf, files); err != nil {
			return err
		}
		buf.Seek(0, 0)
	}

	// Compare on-disk content to the datastore.
	// If the files differ and the timestamp in the datastore is newer, data on disk will be updated.
	// If the files differ and the timestamp on disk is newer, an error will be raised listing the conflicting files.

View on GitHub (pinned to 6ba341e396)

Solutions

  1. If this is the first server, start it with --cluster-init (or point at an existing datastore) so bootstrap data is created.
  2. If joining, verify the --server URL is reachable (https://<ip>:6443/ping) and that the supervisor on the peer is fully started, then restart this node.
  3. Check that DataDir was not changed between restarts, wiping the token/bootstrap files; restore or reinitialize as appropriate.
Defensive patterns

Strategy: validation

Validate before calling

// Before start: require either an initialized datastore or a reachable join server.
func canBootstrap(dataDir string, joinURL string) error {
	if _, err := os.Stat(filepath.Join(dataDir, "db")); err == nil {
		return nil // existing datastore
	}
	if joinURL == "" {
		return errors.New("no datastore and no --server join URL: bootstrap impossible; use --cluster-init")
	}
	resp, err := http.Get(joinURL + "/ping")
	if err != nil || resp.StatusCode != http.StatusOK {
		return errors.New("join server not reachable: " + joinURL)
	}
	return nil
}

Try / catch

if err := startServer(); err != nil {
	if strings.Contains(err.Error(), "no bootstrap data is available to reconcile against") {
		// fatal config: fix --cluster-init / --server / data-dir then relaunch
	}
}

Prevention

When it happens

Trigger: Server configured neither to initialize a new datastore nor able to read one: managedDB path ran but returned nil kv without erroring earlier is impossible here, so this fires when the function is reached without any managed DB and without a successful HTTP bootstrap fetch (join URL unreachable, or storageBootstrap path skipped).

Common situations: Fresh data-dir with no --cluster-init and no reachable --server join URL; join URL points to a peer that is itself not ready; misconfigured DataDir so prior bootstrap files are absent.

Related errors


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