sipeed/picoclaw · error
credential: enc:// passphrase required
Error message
credential: enc:// passphrase required
What it means
Returned by credential.Resolve when a model_list api_key uses the "enc://" scheme but the passphrase source is empty. resolveEncrypted calls PassphraseProvider(), which defaults to reading PICOCLAW_KEY_PASSPHRASE from the environment; an empty string aborts before any crypto runs. Detect it with errors.Is(err, credential.ErrPassphraseRequired).
Source
Thrown at pkg/credential/credential.go:63
const PassphraseEnvVar = "PICOCLAW_KEY_PASSPHRASE"
// PassphraseProvider is the function used to retrieve the passphrase for enc://
// credential decryption. It defaults to reading PICOCLAW_KEY_PASSPHRASE from the
// 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"View on GitHub (pinned to 49183d7e8d)
Solutions
- Export PICOCLAW_KEY_PASSPHRASE with the same passphrase used when the key was encrypted: export PICOCLAW_KEY_PASSPHRASE='...'
- If embedding picoclaw, set credential.PassphraseProvider = passphraseStore.Get in main() before any LoadConfig call
- If the environment cannot carry secrets, replace the enc:// value with a file://<name>.key reference next to the config or re-embed the plaintext key
- Double-check the api_key really starts with "enc://" and is not a stray literal that accidentally matches the scheme
Example fix
# before $ picoclaw gateway # config uses enc:// key, no env set # after $ export PICOCLAW_KEY_PASSPHRASE='my-passphrase' $ picoclaw gateway
Defensive patterns
Strategy: validation
Validate before calling
// before LoadConfig, when any api_key may be enc://
func hasEncCredential(cfg *config.Config) bool {
for _, m := range cfg.ModelList {
if strings.HasPrefix(m.APIKey, credential.EncScheme) { return true }
}
return false
}
if hasEncCredential(cfg) && credential.PassphraseProvider() == "" {
return fmt.Errorf("PICOCLAW_KEY_PASSPHRASE required for enc:// credentials")
} Type guard
func isPassphraseRequired(err error) bool {
return errors.Is(err, credential.ErrPassphraseRequired)
} Try / catch
val, err := resolver.Resolve(raw)
if err != nil {
if errors.Is(err, credential.ErrPassphraseRequired) {
// prompt for / load the passphrase, then retry Resolve once
}
return err
} Prevention
- Export PICOCLAW_KEY_PASSPHRASE in every environment that starts the gateway (shell profile, systemd unit, docker env)
- Embedders: assign credential.PassphraseProvider once in main() before any LoadConfig
- Fail fast at startup with a config pre-check instead of at first credential use
When it happens
Trigger: Resolver.Resolve("enc://<base64>") (directly or via LoadConfig) while PICOCLAW_KEY_PASSPHRASE is unset or empty, and credential.PassphraseProvider has not been replaced with a non-empty source.
Common situations: Config encrypted on machine A (or via the picoclaw CLI) then run on machine B, in systemd/docker/CI where the env var was never exported; an embedded launcher replaced PassphraseProvider with a SecureStore that returns "" until the user unlocks it.
Related errors
- credential: enc:// decryption failed (wrong passphrase or SS
- credential: SSH key path %q is not in an allowed location (P
- credential: file:// path escapes config directory
- credential: passphrase must not be empty
- credential: failed to generate salt: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/9317d9ddb2462ff4.
Report an issue: GitHub.