{"record":{"id":"3acdaa2775745aeb","repo":"sipeed/picoclaw","slug":"credential-enc-invalid-base64-w","errorCode":null,"errorMessage":"credential: enc:// invalid base64: %w","messagePattern":"credential: enc:// invalid base64: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/credential/credential.go","lineNumber":168,"sourceCode":"\t}\n\n\t// Plaintext credential — return unchanged.\n\treturn raw, nil\n}\n\n// resolveEncrypted decrypts an enc:// credential using PassphraseProvider.\nfunc resolveEncrypted(raw string) (string, error) {\n\tpassphrase := PassphraseProvider()\n\tif passphrase == \"\" {\n\t\treturn \"\", ErrPassphraseRequired\n\t}\n\n\tsshKeyPath := pickSSHKeyPath(\"\") // override=\"\": consult env then auto-detect\n\n\tb64 := strings.TrimPrefix(raw, EncScheme)\n\tblob, err := base64.StdEncoding.DecodeString(b64)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"credential: enc:// invalid base64: %w\", err)\n\t}\n\tif len(blob) < saltLen+nonceLen+1 {\n\t\treturn \"\", fmt.Errorf(\"credential: enc:// payload too short\")\n\t}\n\n\tsalt := blob[:saltLen]\n\tnonce := blob[saltLen : saltLen+nonceLen]\n\tciphertext := blob[saltLen+nonceLen:]\n\n\tkey, err := deriveKey(passphrase, sshKeyPath, salt)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tblock, err := aes.NewCipher(key)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"credential: enc:// cipher init: %w\", err)\n\t}\n\tgcm, err := cipher.NewGCM(block)","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/credential/credential.go#L150-L186","documentation":"Returned by resolveEncrypted when the base64 payload after the enc:// prefix cannot be decoded with standard base64. The encrypted credential format is `enc://<std-base64(salt|nonce|ciphertext)>`, so any deviation from strict standard-base64 (base64url characters, missing padding, embedded whitespace/newlines, truncated copy) fails at DecodeString before decryption is attempted.","triggerScenarios":"An enc:// value containing `-` or `_` (base64url alphabet), missing `=` padding, a stray space/quote/newline from copy-paste, or a hand-truncated string. base64.StdEncoding.DecodeString rejects all of these and the error is wrapped.","commonSituations":"Copying enc:// values out of terminals/docs that wrap lines or smart-quote; tooling that emits base64url (JWT-adjacent ecosystems) being used to produce the value; YAML folding inserting whitespace; partial selection when copying.","solutions":["Re-generate the credential with the library's own Encrypt/CLI so the encoding is guaranteed standard base64","If hand-repairing: strip whitespace, convert -/_ to +/, restore padding — or simply re-encrypt, which is safer","Store enc:// values in YAML single-quoted scalars or block literals to prevent line-wrap/folding damage","Verify with `base64 -d <<< '<payload>'` that it decodes before blaming the passphrase"],"exampleFix":"# before (base64url chars, no padding)\napi_key: enc://a-b_c\n\n# after (re-encrypt; std base64 with padding)\napi_key: enc://c2FsdHwxMjM0NTY3ODlweQ==","handlingStrategy":"validation","validationCode":"// Validate enc:// shape before resolving.\nfunc encBase64OK(raw string) error {\n\tif !strings.HasPrefix(raw, \"enc://\") { return nil }\n\t_, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(raw, \"enc://\"))\n\treturn err\n}","typeGuard":"func isStdBase64EncPayload(raw string) bool {\n\tif !strings.HasPrefix(raw, \"enc://\") { return true }\n\t_, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(raw, \"enc://\"))\n\treturn err == nil\n}","tryCatchPattern":"if _, err := resolver.Resolve(raw); err != nil {\n\tvar b64Err base64.CorruptInputError\n\tif errors.As(err, &b64Err) {\n\t\t// transport/copy corruption — re-copy the value or re-encrypt; not a passphrase problem\n\t}\n\treturn err\n}","preventionTips":["Only produce enc:// values via the library's Encrypt/CLI","Store them in quoted YAML scalars or block literals to avoid wrap/fold damage","Diff copied values against the source when decryption setup 'mysteriously' fails"],"tags":["go","credentials","encryption","base64","encoding"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}