{"record":{"id":"aad178304f19b63f","repo":"k3s-io/k3s","slug":"missing-s-directory-from-data-dir","errorCode":null,"errorMessage":"missing %s directory from ${data-dir}","messagePattern":"missing (.+?) directory from (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"pkg/cluster/bootstrap.go","lineNumber":183,"sourceCode":"// An error is returned if any dirs are missing or empty.\nfunc (c *Cluster) checkCertDirs() error {\n\tbootstrapDirs := []string{\n\t\t\"cred\",\n\t\t\"tls\",\n\t\t\"tls/etcd\",\n\t}\n\n\tconst (\n\t\tmissingDir = \"missing %s directory from ${data-dir}\"\n\t\temptyDir   = \"%s directory is empty\"\n\t)\n\n\tfor _, dir := range bootstrapDirs {\n\t\td := filepath.Join(c.config.DataDir, dir)\n\t\tif _, err := os.Stat(d); os.IsNotExist(err) {\n\t\t\terrMsg := fmt.Sprintf(missingDir, d)\n\t\t\tlogrus.Debug(errMsg)\n\t\t\treturn errors.New(errMsg)\n\t\t}\n\n\t\tok, err := isDirEmpty(d)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif ok {\n\t\t\terrMsg := fmt.Sprintf(emptyDir, d)\n\t\t\tlogrus.Debug(errMsg)\n\t\t\treturn errors.New(errMsg)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// migrateBootstrapData migrates bootstrap data from the old format to the new format.","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/k3s-io/k3s/blob/6ba341e396edc16b8dcae978a7c5e3ac7ee5606e/pkg/cluster/bootstrap.go#L165-L201","documentation":"checkCertDirs verifies that <data-dir>/cred, <data-dir>/tls and <data-dir>/tls/etcd exist once storage is ready (pkg/cluster/bootstrap.go:167). A missing directory means the server's credentials and PKI material were never created or were deleted, so k3s aborts startup instead of proceeding with half-present security state.","triggerScenarios":"Server data-dir where any of cred/, tls/ or tls/etcd/ is absent — e.g. after a partial `rm -rf` of /var/lib/rancher/k3s/server, an incomplete data-dir restore, or pointing --data-dir at a directory that never held a server.","commonSituations":"Operators deleting cert subdirectories to force regeneration; backups that missed hidden files or subdirs; wrong --data-dir after moving storage; interrupted cluster resets.","solutions":["Point --data-dir at the complete server data directory (the one containing cred/, tls/, db/)","Restore the missing directories from a full data-dir backup or an etcd snapshot restore flow","If the node is meant to be fresh, wipe the data-dir entirely and re-join so bootstrap recreates the layout coherently"],"exampleFix":"# before\ndata-dir: /var/lib/rancher/k3s/server2   # never initialized as a server\n\n# after\ndata-dir: /var/lib/rancher/k3s/server    # complete layout: cred/, tls/, tls/etcd/, db/","handlingStrategy":"validation","validationCode":"// preflight: required server PKI directories exist\nfor _, d := range []string{\"cred\", \"tls\", \"tls/etcd\"} {\n    p := filepath.Join(dataDir, d)\n    if fi, err := os.Stat(p); err != nil || !fi.IsDir() {\n        return fmt.Errorf(\"missing %s directory from data-dir\", p)\n    }\n}","typeGuard":"func hasCompleteServerPKI(dataDir string) bool {\n    for _, d := range []string{\"cred\", \"tls\", \"tls/etcd\"} {\n        if fi, err := os.Stat(filepath.Join(dataDir, d)); err != nil || !fi.IsDir() {\n            return false\n        }\n    }\n    return true\n}","tryCatchPattern":null,"preventionTips":["Back up the whole data-dir (not selected files) including cred/ and tls/","Never delete individual PKI subdirectories to 'force regeneration'","Verify data-dir completeness after restores with a scripted check before starting k3s"],"tags":["bootstrap","certificates","data-dir","recovery"],"backgroundTag":null,"analyzedSha":"6ba341e396edc16b8dcae978a7c5e3ac7ee5606e","analyzedAt":"2026-08-15T16:27:54.286Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}