FiloSottile/age · warning

failed to re-serialize header

Error message

failed to re-serialize header: %w

What it means

After parsing, Inspect re-serializes the header with hdr.Marshal into a bytes.Buffer to measure its size. Writes to a bytes.Buffer only fail on OOM, so this is nearly impossible in practice; the wrap exists for completeness of the error path.

Solutions

  1. Check available memory if processing pathological inputs
  2. Reduce the number of recipient stanzas when generating files
  3. Report a bug if this reproduces with normal files — it indicates a Marshal implementation issue
Defensive patterns

Strategy: fallback

Validate before calling

// Marshal targets a bytes.Buffer; nothing useful can be validated beforehand.

Type guard

if err != nil { /* treat as OOM/systemic; retry or abort */ }

Try / catch

var buf bytes.Buffer
if err := hdr.Marshal(&buf); err != nil {
    return nil, fmt.Errorf("header re-serialization failed (memory?): %w", err)
}

Prevention

When it happens

Trigger: hdr.Marshal(buf) returns non-nil while Inspect measures data.Sizes.Header — effectively only under memory exhaustion or a custom Marshal failure.

Common situations: Extremely large headers with the maximum number of recipient stanzas on memory-constrained systems; essentially never in normal use.

Related errors


AI-assisted analysis of FiloSottile/age@b74dce4cdb (2026-08-31). Data as JSON: /api/errors/0f1bc212b47af104. Report an issue: GitHub.

Appendix: source

Thrown at internal/inspect/inspect.go:57

	tr := &trackReader{r: r}
	br := bufio.NewReader(tr)
	const maxWhitespace = 1024
	start, _ := br.Peek(maxWhitespace + len(armor.Header))
	if strings.HasPrefix(string(bytes.TrimSpace(start)), armor.Header) {
		r = armor.NewReader(br)
		data.Armor = true
	} else {
		r = br
	}

	hdr, rest, err := format.Parse(r)
	if err != nil {
		return nil, fmt.Errorf("failed to read header: %w", err)
	}

	buf := &bytes.Buffer{}
	if err := hdr.Marshal(buf); err != nil {
		return nil, fmt.Errorf("failed to re-serialize header: %w", err)
	}
	data.Sizes.Header = int64(buf.Len())

	for _, s := range hdr.Recipients {
		data.StanzaTypes = append(data.StanzaTypes, s.Type)
		switch s.Type {
		case "X25519", "ssh-rsa", "ssh-ed25519", "p256tag", "piv-p256":
			data.Postquantum = "no"
		case "mlkem768x25519", "scrypt", "mlkem768p256tag":
			// Keep "yes".
		default:
			if data.Postquantum != "no" {
				data.Postquantum = "unknown"
			}
		}
	}

	// If fileSize is not provided, or if it's the size of the armored file

View on GitHub (pinned to b74dce4cdb)