sipeed/picoclaw · error
credential: enc:// decryption failed (wrong passphrase or SS
Error message
credential: enc:// decryption failed (wrong passphrase or SSH key?)
What it means
Returned when AES-256-GCM authentication fails while decrypting an enc:// credential (gcm.Open error, wrapped as ErrDecryptionFailed). The key is derived via HKDF-SHA256 from ikm=HMAC-SHA256(SHA256(sshKeyBytes), passphrase), so a wrong passphrase OR a different SSH key file both produce a different key and the same failure. Corrupted/truncated ciphertext fails the same way.
Source
Thrown at pkg/credential/credential.go:67
// process environment. Replace it at startup to use a different source, such as
// an in-memory SecureStore, so that all LoadConfig() calls everywhere share the
// same passphrase source without needing os.Environ.
//
// Example (launcher main.go):
//
// credential.PassphraseProvider = apiHandler.passphraseStore.Get
var PassphraseProvider func() string = func() string {
return os.Getenv(PassphraseEnvVar)
}
// ErrPassphraseRequired is returned when an enc:// credential is encountered but
// no passphrase is available from PassphraseProvider. Callers can detect this
// with errors.Is to distinguish a missing-passphrase condition from other errors.
var ErrPassphraseRequired = errors.New("credential: enc:// passphrase required")
// ErrDecryptionFailed is returned when an enc:// credential cannot be decrypted,
// indicating a wrong passphrase or SSH key. Callers can detect this with errors.Is.
var ErrDecryptionFailed = errors.New("credential: enc:// decryption failed (wrong passphrase or SSH key?)")
// SSHKeyPathEnvVar is the environment variable that specifies the path to the
// SSH private key used for enc:// credential encryption and decryption.
const SSHKeyPathEnvVar = "PICOCLAW_SSH_KEY_PATH"
// picoclawHome is a package-local copy of config.EnvHome. It is kept here to
// avoid a circular import between pkg/credential and pkg/config.
const picoclawHome = "PICOCLAW_HOME"
const (
FileScheme = "file://"
EncScheme = "enc://"
hkdfInfo = "picoclaw-credential-v1"
saltLen = 16
nonceLen = 12
keyLen = 32
)View on GitHub (pinned to 49183d7e8d)
Solutions
- Re-enter the exact passphrase used at encryption time into PICOCLAW_KEY_PASSPHRASE
- Restore or point to the original SSH key: export PICOCLAW_SSH_KEY_PATH=/path/to/key_used_when_encrypting (key bytes are part of key derivation)
- If the original key material is gone, re-encrypt the credential with credential.Encrypt(currentPassphrase, currentKeyPath, plaintext) and update the config
- Verify the enc:// blob is intact: single line, valid base64, no truncation from YAML quoting or editor reflow
Example fix
// before: key regenerated, old enc:// value no longer decrypts // after: re-encrypt with current key material enc, err := credential.Encrypt(passphrase, "/home/user/.ssh/picoclaw_ed25519.key", "sk-abc123") // write enc into model_list api_key
Defensive patterns
Strategy: try-catch
Type guard
func isDecryptionFailed(err error) bool {
return errors.Is(err, credential.ErrDecryptionFailed)
} Try / catch
val, err := resolver.Resolve(raw)
if err != nil {
if errors.Is(err, credential.ErrDecryptionFailed) {
// wrong passphrase OR wrong SSH key: surface a 're-enter passphrase / restore key' prompt;
// do NOT brute-force retry in a loop
}
return err
} Prevention
- Back up the exact SSH key used for encryption (PICOCLAW_SSH_KEY_PATH or ~/.ssh/picoclaw_ed25519.key) together with the passphrase
- After rotating the SSH key, re-encrypt all enc:// credentials before deleting the old key
- Keep enc:// blobs on a single line and quote them in YAML to prevent truncation/reflow
When it happens
Trigger: resolveEncrypted on a valid enc:// payload with: (a) PICOCLAW_KEY_PASSPHRASE differing from the encrypt-time passphrase, (b) the SSH key resolved via PICOCLAW_SSH_KEY_PATH or ~/.ssh/picoclaw_ed25519.key differing (by bytes) from the key used by Encrypt, or (c) a base64 blob mangled in transit (quotes/reflow in YAML, truncated line).
Common situations: Rotated or regenerated ~/.ssh/picoclaw_ed25519.key after encrypting keys; typos in the passphrase; copying config between hosts with different default keys; the key file in PICOCLAW_SSH_KEY_PATH pointing at a different machine's key.
Related errors
- credential: enc:// passphrase required
- credential: SSH key path %q is not in an allowed location (P
- create crypto helper: %w
- decrypt media: %w
- credential: file:// path escapes config directory
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/9fdf51526f064955.
Report an issue: GitHub.