ory/hydra · error
plaintext too large
Error message
plaintext too large
What it means
Encrypt computes the ciphertext size as plaintext length + nonce size + Poly1305 overhead and guards the addition against integer overflow before allocating. A plaintext larger than math.MaxInt minus these fixed overheads cannot be safely encrypted, so Encrypt rejects it up front.
Source
Thrown at aead/xchacha20.go:43
func NewXChaCha20Poly1305(d Dependencies) *XChaCha20Poly1305 {
return &XChaCha20Poly1305{d}
}
func (x *XChaCha20Poly1305) Encrypt(ctx context.Context, plaintext, additionalData []byte) (string, error) {
key, err := encryptionKey(ctx, x.d, chacha20poly1305.KeySize)
if err != nil {
return "", err
}
aead, err := chacha20poly1305.NewX(key)
if err != nil {
return "", errors.WithStack(err)
}
// Make sure the size calculation does not overflow.
if len(plaintext) > math.MaxInt-aead.NonceSize()-aead.Overhead() {
return "", errors.WithStack(fmt.Errorf("plaintext too large"))
}
nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(plaintext)+aead.Overhead())
_, err = cryptorand.Read(nonce)
if err != nil {
return "", errors.WithStack(err)
}
ciphertext := aead.Seal(nonce, nonce, plaintext, additionalData)
return base64.URLEncoding.EncodeToString(ciphertext), nil
}
func (x *XChaCha20Poly1305) Decrypt(ctx context.Context, ciphertext string, aad []byte) (plaintext []byte, err error) {
msg, err := base64.URLEncoding.DecodeString(ciphertext)
if err != nil {
return nil, errors.WithStack(err)
}
View on GitHub (pinned to 4174065ffb)
Solutions
- Reduce the plaintext size; do not encrypt arbitrary-size payloads with AEAD — encrypt a content key instead and use streaming encryption for the payload.
- Split large data into chunks encrypted independently.
- If the input comes from user uploads, enforce a size limit before calling Encrypt.
- Fix code paths that read unbounded input into a single byte slice.
Example fix
// before
blob, _ := io.ReadAll(r.Body)
enc, err := x.Encrypt(ctx, blob)
// after
if r.ContentLength > maxPayload { http.Error(w, "too large", 413); return }
blob, _ := io.ReadAll(io.LimitReader(r.Body, maxPayload))
enc, err := x.Encrypt(ctx, blob) Defensive patterns
Strategy: validation
Validate before calling
const maxPlaintext = 1 << 20 // choose a sane app-level limit
if len(plaintext) > maxPlaintext {
return fmt.Errorf("payload too large to encrypt: %d bytes", len(plaintext))
} Try / catch
enc, err := x.Encrypt(ctx, plaintext)
if err != nil && strings.Contains(err.Error(), "plaintext too large") {
return nil, ErrPayloadTooLarge
} Prevention
- Enforce application-level size limits before encrypting.
- Encrypt symmetric content keys, not raw large payloads; use streaming AEAD for big data.
- Avoid io.ReadAll on untrusted input destined for encryption.
- Be extra careful with plaintext sizes on 32-bit platforms.
When it happens
Trigger: Calling Encrypt with a plaintext whose length exceeds math.MaxInt - chacha20poly1305.NonceSizeX - overhead (practically an enormous buffer, near the platform max int).
Common situations: Accidentally passing a streamed file read entirely into memory; a bug where an unbounded/uninitialized buffer is encrypted; 32-bit builds where MaxInt is small enough that large request bodies trip the check.
Related errors
- key must be exactly %d bytes long, got %d bytes
- at least one encryption key must be defined but none were
- malformed ciphertext: too short
- unknown algorithm %s for encryption key
- key must be exactly 32 long bytes, got %d bytes
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/3946ec7acf183f13.
Report an issue: GitHub.