k3s-io/k3s · error
failed to create path for symlink: %v
Error message
failed to create path for symlink: %v
What it means
Before creating the kubeconfig symlink, k3s ensures its parent directory exists with os.MkdirAll (typically /etc/rancher/k3s). Failure of that mkdir - permission denied, path component is a file, read-only or immutable filesystem - is returned as this error during server startup.
Source
Thrown at pkg/server/server.go:530
envList := []string{}
envList = append(envList, strings.FieldsFunc(os.Getenv("NO_PROXY"), splitter)...)
envList = append(envList, strings.FieldsFunc(os.Getenv("no_proxy"), splitter)...)
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
}View on GitHub (pinned to 6ba341e396)
Solutions
- Check the path shape: ls -ld /etc/rancher /etc/rancher/k3s - remove any regular file occupying a needed directory component.
- Run k3s as root (or the systemd unit) so it can create /etc/rancher/k3s, or pre-create the directory owned by the runtime user.
- In containers, ensure /etc/rancher is a writable volume/mount.
- Address any filesystem-level cause (read-only mount, SELinux denial) shown by the wrapped %v error.
Example fix
# before: /etc/rancher is a file ls -ld /etc/rancher # '-rw-r--r-- a file' # after sudo rm /etc/rancher && sudo mkdir -p /etc/rancher/k3s && sudo systemctl restart k3s
Defensive patterns
Strategy: validation
Validate before calling
// Ensure the symlink parent dir is a writable directory before start
if fi, err := os.Stat(dir); err == nil && !fi.IsDir() {
log.Fatalf("%s exists but is not a directory", dir)
} else if err := os.MkdirAll(dir, 0755); err != nil {
log.Fatalf("cannot create %s: %v", dir, err)
} Prevention
- Pre-create /etc/rancher/k3s with correct ownership in provisioning
- Run k3s via its systemd unit (root) or grant the runtime user write access
- Mount /etc/rancher as a writable volume in containers
When it happens
Trigger: Server start where MkdirAll(/etc/rancher/k3s) fails: running k3s as a non-root user without write access to /etc, /etc/rancher existing as a regular file, a read-only root filesystem (immutable appliances, containers without writable /etc), or SELinux denial.
Common situations: Running the k3s binary manually as an unprivileged user instead of via the systemd unit; containerized deployments missing a writable /etc mount; a file accidentally created at /etc/rancher; disk or filesystem errors (I/O errors surface here too).
Related errors
- failed to remove %s file: %v
- failed to create 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/1a453a300d1531b4.
Report an issue: GitHub.