{"record":{"id":"30e181dc3ec2bdaa","repo":"semaphoreui/semaphore","slug":"encryption-keys-keys-folder-q-w","errorCode":null,"errorMessage":"encryption_keys.keys_folder %q: %w","messagePattern":"encryption_keys\\.keys_folder %q: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/config.go","lineNumber":1576,"sourceCode":"\t\t\treturn \"\", fmt.Errorf(\"encryption_keys.active.%s_key_file: %w\", kind, err)\n\t\t}\n\t\tmaterial := strings.TrimSpace(string(data))\n\t\tif err := addLabeled(file, material); err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\treturn material, nil\n\t}\n\n\treturn flat, nil\n}\n\n// loadKeysFolder reads every regular file in folder as one key, labelled by its\n// filename. Dot-prefixed entries (e.g. Kubernetes' \"..data\" / \"..2024_*\") are\n// skipped; symlinks (how K8s mounts secret files) are followed via Stat.\nfunc loadKeysFolder(folder string, addLabeled func(string, string) error) error {\n\tentries, err := os.ReadDir(folder)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"encryption_keys.keys_folder %q: %w\", folder, err)\n\t}\n\tfor _, e := range entries {\n\t\tname := e.Name()\n\t\tif strings.HasPrefix(name, \".\") {\n\t\t\tcontinue\n\t\t}\n\t\tpath := filepath.Join(folder, name)\n\t\tinfo, err := os.Stat(path) // follow symlink\n\t\tif err != nil || !info.Mode().IsRegular() {\n\t\t\tcontinue\n\t\t}\n\t\tdata, err := os.ReadFile(path)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"encryption_keys.keys_folder: read %q: %w\", name, err)\n\t\t}\n\t\tif err := addLabeled(name, strings.TrimSpace(string(data))); err != nil {\n\t\t\treturn fmt.Errorf(\"encryption_keys.keys_folder: key %q: %w\", name, err)\n\t\t}","sourceCodeStart":1558,"sourceCodeEnd":1594,"githubUrl":"https://github.com/semaphoreui/semaphore/blob/1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa/util/config.go#L1558-L1594","documentation":"loadKeysFolder wraps the os.ReadDir failure when encryption_keys.keys_folder cannot be listed. The wrapped OS error indicates the folder does not exist, is not a directory, or is not readable by the semaphore process.","triggerScenarios":"keys_folder set to a path that was never created/mounted; path is a file, not a directory; permission denied for the process user; typo in the mounted volume path.","commonSituations":"Kubernetes secret volume mounted at a different mountPath than configured; Docker volume not mounted in the container; directory created only on the host, not in the image; wrong ownership after chown.","solutions":["Create the folder or fix the path: `mkdir -p <folder>` and place key files there","Mount the volume/secret at the exact configured keys_folder path in your deployment","Fix directory permissions (read+execute for the semaphore process user)","Verify from inside the container: `ls -la <folder>`"],"exampleFix":"# before\nencryption_keys:\n  keys_folder: /etc/semaphore/keys   # never mounted\n# after (K8s)\nvolumes:\n  - name: enc-keys\n    secret: {secretName: semaphore-enc-keys}\nvolumeMounts:\n  - {name: enc-keys, mountPath: /etc/semaphore/keys, readOnly: true}\nencryption_keys:\n  keys_folder: /etc/semaphore/keys","handlingStrategy":"validation","validationCode":"if cfg.Encryption != nil && cfg.Encryption.KeysFolder != \"\" {\n    info, err := os.Stat(cfg.Encryption.KeysFolder)\n    if err != nil || !info.IsDir() {\n        return fmt.Errorf(\"keys_folder %s is not a readable directory\", cfg.Encryption.KeysFolder)\n    }\n}","typeGuard":"func isReadableDir(path string) bool {\n    info, err := os.Stat(path)\n    return err == nil && info.IsDir()\n}","tryCatchPattern":"if err := loadKeysFolder(folder, addLabeled); err != nil {\n    return fmt.Errorf(\"cannot load encryption keys: %w\", err)\n}","preventionTips":["Match volumeMount mountPath in K8s/Docker exactly to keys_folder","Create the directory in the image or entrypoint if keys are optional at mount time","Run the container as a user with read+execute on the keys directory","Smoke-test `ls -la <keys_folder>` inside the container as part of deployment checks"],"tags":["config","encryption","directory","filesystem","semaphore"],"backgroundTag":"directory-not-found","analyzedSha":"1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa","analyzedAt":"2026-09-07T11:00:33.293Z","contentChangedAt":"2026-09-07T11:00:33.293Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}