sipeed/picoclaw · error
credential: cannot determine home directory: %w
Error message
credential: cannot determine home directory: %w
What it means
DefaultSSHKeyPath calls os.UserHomeDir, which reads $HOME on Unix (%USERPROFILE% on Windows) and errors when it is empty. The picoclaw credential layer then cannot compute ~/.ssh/picoclaw_ed25519.key for key auto-detection or keygen defaulting. The underlying error is wrapped, so it is diagnosable via err.Error() text from the environment API.
Source
Thrown at pkg/credential/keygen.go:19
package credential
import (
"crypto/ed25519"
"crypto/rand"
"encoding/pem"
"fmt"
"os"
"path/filepath"
"golang.org/x/crypto/ssh"
)
// DefaultSSHKeyPath returns the canonical path for the picoclaw-specific SSH key.
// The path is always ~/.ssh/picoclaw_ed25519.key (os.UserHomeDir is cross-platform).
func DefaultSSHKeyPath() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", fmt.Errorf("credential: cannot determine home directory: %w", err)
}
return filepath.Join(home, ".ssh", "picoclaw_ed25519.key"), nil
}
// GenerateSSHKey generates an Ed25519 SSH key pair and writes the private key
// to path (permissions 0600) and the public key to path+".pub" (permissions 0644).
// The ~/.ssh/ directory is created with 0700 if it does not exist.
// If the files already exist they are overwritten.
func GenerateSSHKey(path string) error {
if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {
return fmt.Errorf("credential: keygen: cannot create directory %q: %w", filepath.Dir(path), err)
}
pubRaw, privRaw, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
return fmt.Errorf("credential: keygen: ed25519 key generation failed: %w", err)
}
View on GitHub (pinned to 49183d7e8d)
Solutions
- Set HOME explicitly in the service environment: systemd `Environment="HOME=/var/lib/picoclaw"`, docker `-e HOME=/root`, or `sudo -E`
- Bypass home lookup entirely: export PICOCLAW_SSH_KEY_PATH=<absolute key path>, which pickSSHKeyPath honors before auto-detection
- For containers, add `ENV HOME=/root` (or the USER's home) to the Dockerfile
Example fix
# before: systemd unit with no HOME [Service] ExecStart=/usr/local/bin/picoclaw # after: explicit home (or bypass via key path env) [Service] Environment="HOME=/var/lib/picoclaw" # alternative: Environment="PICOCLAW_SSH_KEY_PATH=/etc/picoclaw/picoclaw_ed25519.key" ExecStart=/usr/local/bin/picoclaw
Defensive patterns
Strategy: validation
Validate before calling
func homeResolved() error {
if os.Getenv("HOME") == "" { // covers the Unix UserHomeDir failure
return fmt.Errorf("HOME is not set; set HOME or PICOCLAW_SSH_KEY_PATH")
}
return nil
} Prevention
- Set HOME explicitly in systemd units, cron entries, and container envs
- Prefer PICOCLAW_SSH_KEY_PATH for servers - it bypasses home-directory resolution entirely
- In Dockerfiles, set ENV HOME when using USER with a nonstandard home
- Smoke-test deployments with `env -i` locally to catch missing-env assumptions
When it happens
Trigger: Calling DefaultSSHKeyPath (directly or via findDefaultSSHKey / GenerateSSHKey defaults) in a process whose environment lacks HOME: bare systemd services without Environment=, cron jobs, `sudo` without -E, docker run without -e HOME, env -i wrappers, or some CI runners.
Common situations: Deploying the daemon as a systemd unit and forgetting Environment="HOME=/var/lib/picoclaw"; Docker images using USER without setting HOME for that uid; running via crontab where HOME may be unset; macOS launchd agents.
Related errors
- credential: enc:// passphrase required
- udevadm start: %w (is udevadm installed?)
- credential: enc:// decryption failed (wrong passphrase or SS
- host cannot be empty
- host list contains an empty entry
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/69086fe9790eea89.
Report an issue: GitHub.