{"record":{"id":"1731944790a9d987","repo":"sipeed/picoclaw","slug":"credential-keygen-cannot-create-directory-q-w","errorCode":null,"errorMessage":"credential: keygen: cannot create directory %q: %w","messagePattern":"credential: keygen: cannot create directory %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/credential/keygen.go","lineNumber":30,"sourceCode":")\n\n// DefaultSSHKeyPath returns the canonical path for the picoclaw-specific SSH key.\n// The path is always ~/.ssh/picoclaw_ed25519.key (os.UserHomeDir is cross-platform).\nfunc DefaultSSHKeyPath() (string, error) {\n\thome, err := os.UserHomeDir()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"credential: cannot determine home directory: %w\", err)\n\t}\n\treturn filepath.Join(home, \".ssh\", \"picoclaw_ed25519.key\"), nil\n}\n\n// GenerateSSHKey generates an Ed25519 SSH key pair and writes the private key\n// to path (permissions 0600) and the public key to path+\".pub\" (permissions 0644).\n// The ~/.ssh/ directory is created with 0700 if it does not exist.\n// If the files already exist they are overwritten.\nfunc GenerateSSHKey(path string) error {\n\tif err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {\n\t\treturn fmt.Errorf(\"credential: keygen: cannot create directory %q: %w\", filepath.Dir(path), err)\n\t}\n\n\tpubRaw, privRaw, err := ed25519.GenerateKey(rand.Reader)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"credential: keygen: ed25519 key generation failed: %w\", err)\n\t}\n\n\t// Marshal private key as OpenSSH PEM.\n\tblock, err := ssh.MarshalPrivateKey(privRaw, \"\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"credential: keygen: marshal private key: %w\", err)\n\t}\n\tprivPEM := pem.EncodeToMemory(block)\n\n\tif err = os.WriteFile(path, privPEM, 0o600); err != nil {\n\t\treturn fmt.Errorf(\"credential: keygen: write private key %q: %w\", path, err)\n\t}\n","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/credential/keygen.go#L12-L48","documentation":"GenerateSSHKey creates the parent directory of the requested key path (normally ~/.ssh) with os.MkdirAll(..., 0700) before writing keys, and wraps any failure here. Typical causes: permission denied on an existing parent, a regular file occupying the directory name, or a read-only filesystem. The failing directory is included in the message.","triggerScenarios":"GenerateSSHKey(path) where filepath.Dir(path) cannot be created: path like /home/alice/.ssh/picoclaw.key while running as a user without write access to /home/alice; a file named .ssh already exists; target directory on a read-only mount (immutable container layer); path with an existing parent owned by root with 0755 when running non-root.","commonSituations":"Keygen run as root for a user's home that has restrictive perms or is NFS-mounted root-squashed; container images with read-only rootfs and no writable volume for keys; leftover file where a directory belongs.","solutions":["Create the directory manually with the right ownership: `install -d -m 700 -o <user> <dir>`","Check nothing occupies the path: `ls -ld <dir>` - if it is a file, remove or rename it","If the filesystem is read-only, choose a key path under a writable volume and point PICOCLAW_SSH_KEY_PATH at it","Run the keygen as the user who will own the key"],"exampleFix":"# before: keygen as root into a user home that is not writable\nsudo picoclaw keygen  # -> cannot create directory \"/home/alice/.ssh\"\n\n# after: pre-create with correct ownership, then keygen as that user\nsudo install -d -m 700 -o alice -g alice /home/alice/.ssh\nsudo -u alice picoclaw keygen","handlingStrategy":"validation","validationCode":"func keyDirReady(path string) error {\n    dir := filepath.Dir(path)\n    if fi, err := os.Stat(dir); err == nil {\n        if !fi.IsDir() {\n            return fmt.Errorf(\"%s exists and is not a directory\", dir)\n        }\n        return nil\n    }\n    return os.MkdirAll(dir, 0o700)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pre-create ~/.ssh with 0700 during provisioning rather than relying on keygen","Run keygen as the user who will own the key","On read-only filesystems, place keys under a writable volume and set PICOCLAW_SSH_KEY_PATH"],"tags":["filesystem","permissions","keygen","ssh","read-only-fs"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}