k3s-io/k3s · error
failed to create symlink: %v
Error message
failed to create symlink: %v
What it means
The final step of writeConfigSymlink calls os.Symlink to point the well-known kubeconfig path at the data-dir kubeconfig. Any failure creating the symlink - most commonly the target path already exists again (race with another process), permission on the parent directory, or symlink privilege restrictions - is returned as this error.
Source
Thrown at pkg/server/server.go:533
envList = append(envList,
".svc",
"."+config.ClusterDomain,
util.JoinIPNets(config.ClusterIPRanges),
util.JoinIPNets(config.ServiceIPRanges),
)
os.Unsetenv("no_proxy")
return os.Setenv("NO_PROXY", strings.Join(envList, ","))
}
func writeConfigSymlink(kubeconfig, kubeconfigSymlink string) error {
if err := os.Remove(kubeconfigSymlink); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("failed to remove %s file: %v", kubeconfigSymlink, err)
}
if err := os.MkdirAll(filepath.Dir(kubeconfigSymlink), 0755); err != nil {
return fmt.Errorf("failed to create path for symlink: %v", err)
}
if err := os.Symlink(kubeconfig, kubeconfigSymlink); err != nil {
return fmt.Errorf("failed to create symlink: %v", err)
}
return nil
}
func isSymlink(config string) bool {
if fi, err := os.Lstat(config); err == nil && (fi.Mode()&os.ModeSymlink == os.ModeSymlink) {
return true
}
return false
}
func setNodeLabelsAndAnnotations(ctx context.Context, nodes v1.NodeClient, config *Config) error {
if config.DisableAgent || config.ControlConfig.DisableAPIServer {
return nil
}
patcher := util.NewPatcher[*corev1.Node](nodes)
return wait.PollUntilContextCancel(ctx, time.Second, true, func(ctx context.Context) (bool, error) {View on GitHub (pinned to 6ba341e396)
Solutions
- Check for and clear the target path: ls -la /etc/rancher/k3s/ and remove a stale k3s.yaml, then restart k3s.
- Ensure only one k3s instance manages a given /etc/rancher directory (check for duplicate systemd units or containers).
- On Windows, run from an elevated shell or enable Developer Mode so unprivileged symlink creation is allowed.
- Confirm write permission on the parent directory and absence of MAC-policy denials in the wrapped error.
Example fix
# before: stale target left by a racing instance ls -l /etc/rancher/k3s/k3s.yaml # regular file, k3s fails at os.Symlink # after sudo rm /etc/rancher/k3s/k3s.yaml && sudo systemctl restart k3s
Defensive patterns
Strategy: retry
Validate before calling
// Check target is absent or already the right symlink before start
if fi, err := os.Lstat(target); err == nil {
if fi.Mode()&os.ModeSymlink != 0 { /* already linked, ok */ } else {
os.Remove(target) // clear regular file left by another tool
}
} Try / catch
// Handle EEXIST-style races by clearing and retrying once
if err := writeConfigSymlink(kc, sym); err != nil {
if strings.Contains(err.Error(), "failed to create symlink") {
os.Remove(sym)
err = writeConfigSymlink(kc, sym) // single deterministic retry
}
if err != nil { return err }
} Prevention
- Ensure exactly one k3s instance manages a given /etc/rancher path
- On Windows, enable Developer Mode or run elevated
- Keep the parent directory writable throughout startup
When it happens
Trigger: Server start where os.Symlink(kubeconfig, kubeconfigSymlink) fails: another k3s instance/loop recreated the path between the Remove and Symlink calls, the parent dir is not writable, or on Windows without the SeCreateSymbolicLinkPrivilege (developer mode / admin requirement).
Common situations: Two k3s servers sharing or racing over the same /etc/rancher path; system hardening that revoked write permission right after startup began; running k3s on Windows hosts without developer mode; antivirus/EDR briefly locking the new symlink.
Related errors
- failed to remove %s file: %v
- failed to create path for symlink: %v
- tar error: %v
- unhandled cgroup mode
- no bootstrap data is available to reconcile against
AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15).
Data as JSON: /api/errors/4e691e72561b0d5a.
Report an issue: GitHub.