semaphoreui/semaphore · error
ciphertext too short
Error message
ciphertext too short
What it means
Returned by DecryptAESGCM in util/encryption.go after base64 decoding succeeds but the decoded byte slice is shorter than the GCM nonce size. A valid AES-GCM payload always contains at least the nonce (typically 12 bytes) followed by the sealed ciphertext, so a shorter input means the value is truncated, empty, or not actually an AES-GCM ciphertext at all — a length guard that prevents an out-of-range slice before calling gcm.Open.
Solutions
- Verify the stored value was produced by EncryptAESGCM and not truncated by a storage layer or manual copy
- Re-encrypt and re-store the secret if the payload is unrecoverable
- If the value is legacy plaintext, use the plaintext path (empty key) or migrate it to the encrypted format
- Check that nothing strips bytes from the encoded string (e.g. trimming '=' padding before decode would already fail earlier)
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at util/encryption.go:55 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of semaphoreui/semaphore@1774ccb71a (2026-09-07).
Data as JSON: /api/errors/d5f2757d43df2c26.
Report an issue: GitHub.
Appendix: source
Thrown at util/encryption.go:55
// DecryptAESGCM decrypts an AES-256-GCM ciphertext.
func DecryptAESGCM(encodedCiphertext, encodedKey string) ([]byte, error) {
ciphertext, err := base64.StdEncoding.DecodeString(encodedCiphertext)
if err != nil {
return nil, fmt.Errorf("base64 decode: %w", err)
}
if encodedKey == "" {
return ciphertext, nil
}
gcm, err := newGCM(encodedKey)
if err != nil {
return nil, err
}
nonceSize := gcm.NonceSize()
if len(ciphertext) < nonceSize {
return nil, errors.New("ciphertext too short")
}
nonce, payload := ciphertext[:nonceSize], ciphertext[nonceSize:]
return gcm.Open(nil, nonce, payload, nil)
}
func newGCM(encodedKey string) (cipher.AEAD, error) {
keyBytes, err := base64.StdEncoding.DecodeString(encodedKey)
if err != nil {
return nil, fmt.Errorf("decode encryption key: %w", err)
}
block, err := aes.NewCipher(keyBytes)
if err != nil {
return nil, err
}
return cipher.NewGCM(block)
}
View on GitHub (pinned to 1774ccb71a)