FiloSottile/age · error
column limit exceeded
Error message
column limit exceeded
What it means
Armor lines are restricted to format.ColumnsPerLine (64) characters, matching the encoder's output. A longer line means the data was not produced by this armor format (or was reformatted), so the reader rejects it instead of guessing how to split it.
Source
Thrown at armor/armor.go:161
continue
}
if string(line) != Header {
return 0, r.setErr(fmt.Errorf("invalid first line: %q", line))
}
r.started = true
}
line, err := getLine()
if err != nil {
return 0, r.setErr(err)
}
if string(line) == Footer {
return 0, r.setErr(drainTrailing())
}
if len(line) == 0 {
return 0, r.setErr(errors.New("empty line in armored data"))
}
if len(line) > format.ColumnsPerLine {
return 0, r.setErr(errors.New("column limit exceeded"))
}
// Reject newline characters ignored by base64.Decode.
if bytes.ContainsAny(line, "\n\r") {
return 0, r.setErr(errors.New("unexpected newline character"))
}
r.unread = r.buf[:]
n, err := base64.StdEncoding.Strict().Decode(r.unread, line)
if err != nil {
return 0, r.setErr(err)
}
r.unread = r.unread[:n]
if n < format.BytesPerLine {
line, err := getLine()
if err != nil {
return 0, r.setErr(err)
}
if string(line) != Footer {View on GitHub (pinned to b74dce4cdb)
Solutions
- Re-wrap body lines to at most 64 columns (e.g. fold -w 64) and retry decryption.
- Re-obtain the armored file from its original source or re-run the age CLI to produce correctly wrapped armor.
- Disable editor word-wrap and avoid MIME re-encoding when transferring .age files.
Example fix
// before: one 200-char base64 line in the armor body // after fold -w 64 longline.age > wrapped.age
Defensive patterns
Strategy: validation
Validate before calling
// Check armor line widths before decrypting
func checkLineLengths(data []byte) error {
for _, l := range bytes.Split(data, []byte('\n')) {
l = bytes.TrimRight(l, "\r")
if !bytes.HasPrefix(l, []byte("-----")) && len(l) > 64 {
return fmt.Errorf("line too long: %d", len(l))
}
}
return nil
} Type guard
func isWrappedArmorLine(line []byte) bool {
return len(line) <= 64
} Try / catch
_, err := io.ReadAll(armor.NewReader(f))
if err != nil && err.Error() == "column limit exceeded" {
// re-wrap lines with fold -w 64 or re-export the armor
} Prevention
- Keep armor lines at the encoder's 64-column width.
- Do not paste base64 from MIME emails (76-char lines) into age armor.
- Disable word-wrap when editing armored files.
When it happens
Trigger: Reading an armored file where a body line exceeds 64 characters — e.g. armor reflowed by a text editor with a different wrap width, MIME base64 from email (76-char lines) pasted into an age armor envelope, or hand-concatenated base64 lines.
Common situations: Extracting base64 from a MIME email attachment into an age armor template, editors with word-wrap rewriting the file, or scripts joining base64 lines into one long line.
Related errors
- trailing data after armored file
- too much trailing whitespace
- too much leading whitespace
- empty line in armored data
- unexpected newline character
AI-assisted analysis of FiloSottile/age@b74dce4cdb (2026-08-31).
Data as JSON: /api/errors/fd39c917730b0b06.
Report an issue: GitHub.