k3s-io/k3s · error

does not exist, please pass --token to complete the restora

Error message

 does not exist, please pass --token to complete the restoration

What it means

When restoring a cluster from a snapshot (--cluster-reset --cluster-reset-restore-path), k3s needs the original cluster token to seed the new cluster. If --token/K3S_TOKEN is empty it falls back to reading <data-dir>/server/token; when that file is also absent the restoration aborts before touching the datastore.

Source

Thrown at pkg/cli/server/server.go:505

		}

		dataDir, err := datadir.LocalHome(cfg.DataDir, false)
		if err != nil {
			return err
		}
		// delete local loadbalancers state for apiserver and supervisor servers
		loadbalancer.ResetLoadBalancer(filepath.Join(dataDir, "agent"), loadbalancer.SupervisorServiceName)
		loadbalancer.ResetLoadBalancer(filepath.Join(dataDir, "agent"), loadbalancer.APIServerServiceName)

		if cfg.ClusterResetRestorePath != "" {
			// at this point we're doing a restore. Check to see if we've
			// passed in a token and if not, check if the token file exists.
			// If it doesn't, return an error indicating the token is necessary.
			if cfg.Token == "" {
				tokenFile := filepath.Join(dataDir, "server", "token")
				if _, err := os.Stat(tokenFile); err != nil {
					if os.IsNotExist(err) {
						return errors.New(tokenFile + " does not exist, please pass --token to complete the restoration")
					}
				}
			}
		}
	}

	logrus.Info("Starting " + version.Program + " " + app.App.Version)

	notifySocket := os.Getenv("NOTIFY_SOCKET")
	os.Unsetenv("NOTIFY_SOCKET")

	// try setting advertise-ip from agent VPN
	if vpnInfo, _ := vpn.GetInfoFromExecutor(); vpnInfo != nil {
		// If we are in ipv6-only mode, we should pass the ipv6 address. Otherwise, ipv4
		if utilsnet.IsIPv6(nodeIPs[0]) {
			if vpnInfo.IPv6Address != nil {
				logrus.Infof("Changed advertise-address to %v due to VPN", vpnInfo.IPv6Address)
				if serverConfig.ControlConfig.AdvertiseIP != "" {

View on GitHub (pinned to 6ba341e396)

Solutions

  1. Pass the original cluster token: `--token <value>` or `K3S_TOKEN=<value>` (it must match the token used when the snapshot was taken for nodes to rejoin)
  2. Restore <data-dir>/server/token from a backup copy if the original token value is unknown
  3. Keep the cluster token in a secret manager at cluster creation time so restores are always possible

Example fix

# before
k3s server --cluster-reset --cluster-reset-restore-path=/backups/etcd-snapshot.zip

# after
K3S_TOKEN=<original-cluster-token> k3s server --cluster-reset --cluster-reset-restore-path=/backups/etcd-snapshot.zip
Defensive patterns

Strategy: validation

Validate before calling

# guard before restore
if [ -n "$RESTORE_PATH" ] && [ -z "$K3S_TOKEN" ] && [ ! -s /var/lib/rancher/k3s/server/token ]; then
  echo 'token required for cluster-reset restore'; exit 1
fi

Prevention

When it happens

Trigger: `k3s server --cluster-reset --cluster-reset-restore-path=<snap>` with no --token and no <data-dir>/server/token file — typical when restoring onto a wiped or brand-new node.

Common situations: Disaster recovery onto new hardware where the data-dir was freshly created; cleanup scripts that deleted the token file; operators assuming the token is embedded in the snapshot.

Related errors


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