FiloSottile/age · error
failed to compute tag: %v
Error message
failed to compute tag: %v
What it means
After validating enc's length, Tag derives the 4-byte tag with crypto/hkdf.Extract over SHA-256. HKDF-Extract in the standard library effectively cannot fail with these fixed inputs; this wrap exists to satisfy error handling and would only surface on an unexpected crypto/hkdf implementation failure.
Source
Thrown at tag/tag.go:124
//
// This is a low-level method exposed for use by plugins that implement
// identities compatible with tagged recipients.
func (r *Recipient) Tag(enc []byte) ([]byte, error) {
label, tagRecipient := "age-encryption.org/p256tag", r.Bytes()
if r.Hybrid() {
label = "age-encryption.org/mlkem768p256tag"
// In hybrid mode, the tag is computed over just the P-256 part.
tagRecipient = tagRecipient[mlkem.EncapsulationKeySize768:]
if len(enc) != mlkem.CiphertextSize768+uncompressedPointSize {
return nil, fmt.Errorf("invalid ciphertext size")
}
} else if len(enc) != uncompressedPointSize {
return nil, fmt.Errorf("invalid ciphertext size")
}
rh := sha256.Sum256(tagRecipient)
tag, err := hkdf.Extract(sha256.New, append(slices.Clip(enc), rh[:4]...), []byte(label))
if err != nil {
return nil, fmt.Errorf("failed to compute tag: %v", err)
}
return tag[:4], nil
}
// WrapWithLabels implements [age.RecipientWithLabels], returning a single
// "postquantum" label if r is a hybrid P-256 + ML-KEM-768 recipient. This
// ensures a hybrid Recipient can't be mixed with other recipients that would
// defeat its post-quantum security.
//
// To unsafely bypass this restriction, wrap Recipient in an [age.Recipient]
// type that doesn't expose WrapWithLabels.
func (r *Recipient) WrapWithLabels(fileKey []byte) ([]*age.Stanza, []string, error) {
label, arg := "age-encryption.org/p256tag", "p256tag"
if r.Hybrid() {
label, arg = "age-encryption.org/mlkem768p256tag", "mlkem768p256tag"
}
enc, s, err := hpke.NewSender(r.pk, hpke.HKDFSHA256(), hpke.ChaCha20Poly1305(), []byte(label))View on GitHub (pinned to b74dce4cdb)
Solutions
- Use the standard library crypto/hkdf package (Go 1.24+) rather than a forked or shimmed implementation.
- Retry the operation once to rule out transient backend failure.
- If it persists, report the underlying wrapped error (%v detail) upstream to the age project.
Defensive patterns
Strategy: try-catch
Validate before calling
// Not applicable: inputs are already length-validated before hkdf.Extract; failure is not caller-preventable.
Try / catch
tag, err := r.Tag(enc)
if err != nil {
return fmt.Errorf("HKDF tag derivation failed: %w", err)
} Prevention
- Use standard crypto/hkdf (Go 1.24+), not forks.
- Keep Go toolchain and dependencies current.
- Retry once to rule out transient backend failure.
When it happens
Trigger: Practically unreachable with crypto/hkdf from the standard library given sha256.New and fixed-length inputs; would require a failing HKDF implementation if the crypto backend is swapped.
Common situations: Almost never seen in the field; occasionally reported when a custom/forked crypto/hkdf package or exotic build constraint alters behavior.
Related errors
- failed to decrypt and authenticate final chunk: %w
- failed to decrypt and authenticate chunk at offset %d: %w
- wrong ecdh Curve
- failed to create hybrid public key: %v
- invalid tag recipient public key size %d
AI-assisted analysis of FiloSottile/age@b74dce4cdb (2026-08-31).
Data as JSON: /api/errors/19dbee50ac88d17e.
Report an issue: GitHub.