JuliusBrussee/caveman · error
kms: plaintext exceeds
Error message
kms: plaintext exceeds %d bytes
What it means
Encrypt rejects plaintext larger than maxPlaintextBytes because the Scaleway Key Manager API has a hard payload size limit; oversized input would only fail later at the HTTP layer. The error reports the exact byte cap via %d.
Solutions
- Check len(plaintext) against the library's limit before calling and split or reject oversized input.
- Encrypt a small data-encryption key (DEK) and use it for bulk data locally (envelope encryption).
- Chunk large payloads into multiple Encrypt calls and concatenate the envelopes.
Example fix
// before
enc, err := client.Encrypt(ctx, bigFileBytes) // kms: plaintext exceeds N bytes
// after
const maxPlaintext = 32 << 10 // consult kms.maxPlaintextBytes
if len(bigFileBytes) > maxPlaintext {
return fmt.Errorf("payload %d bytes exceeds KMS limit %d", len(bigFileBytes), maxPlaintext)
}
enc, err := client.Encrypt(ctx, bigFileBytes) Defensive patterns
Strategy: validation
Validate before calling
if len(plaintext) == 0 {
return errors.New("nothing to encrypt")
}
if len(plaintext) > maxPlaintextBytes {
return fmt.Errorf("plaintext %d > limit %d; use envelope encryption", len(plaintext), maxPlaintextBytes)
} Try / catch
enc, err := client.Encrypt(ctx, plaintext)
if err != nil {
if strings.Contains(err.Error(), "exceeds") {
return fmt.Errorf("payload too large for KMS: %w", err)
}
return err
} Prevention
- Encrypt only small DEKs; do bulk encryption locally.
- Check len(plaintext) before every Encrypt call.
- Chunk large blobs rather than raising limits.
- Document the size cap wherever the client is constructed.
When it happens
Trigger: Calling client.Encrypt(ctx, plaintext) with len(plaintext) > maxPlaintextBytes, e.g. encrypting a whole file, a large token blob, or concatenated secrets in one call.
Common situations: Encrypting database rows or config files wholesale instead of a data-encryption key; skipping chunking when migrating from a KMS without size limits.
Understand the failure class
Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.
Related errors
- kms: probe encrypt
- secretbox: KMS encrypt
- secretbox: payload KMS encrypt
- secretbox: production requires CAVE_KMS_PROVIDER=scaleway
- aes cipher
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/11bc25c5e3a6c6c8.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/kms/kms.go:180
return client.Encrypt(ctx, plaintext)
}
// EncryptPayload wraps an artifact data key with the dedicated payload KEK.
func EncryptPayload(ctx context.Context, plaintext []byte) ([]byte, error) {
client, err := FromPayloadEnvironment()
if err != nil {
return nil, err
}
return client.Encrypt(ctx, plaintext)
}
// Encrypt delegates encryption to key manager.
func (c *Client) Encrypt(ctx context.Context, plaintext []byte) ([]byte, error) {
if len(plaintext) == 0 {
return nil, errors.New("kms: plaintext is empty")
}
if len(plaintext) > maxPlaintextBytes {
return nil, fmt.Errorf("kms: plaintext exceeds %d bytes", maxPlaintextBytes)
}
var response struct {
KeyID string `json:"key_id"`
Ciphertext string `json:"ciphertext"`
}
if err := c.call(ctx, c.region, c.keyID, "encrypt", map[string]string{
"plaintext": base64.StdEncoding.EncodeToString(plaintext),
}, &response); err != nil {
return nil, err
}
if response.KeyID != c.keyID || strings.TrimSpace(response.Ciphertext) == "" {
return nil, errors.New("kms: invalid encrypt response")
}
envelope, err := json.Marshal(Envelope{Provider: c.provider, Region: c.region, KeyID: response.KeyID, Ciphertext: response.Ciphertext})
if err != nil {
return nil, fmt.Errorf("kms: encode envelope: %w", err)
}
return append([]byte(prefix), envelope...), nilView on GitHub (pinned to 3ee70a1026)