FiloSottile/age · error
failed to read line: %w
Error message
failed to read line: %w
What it means
ReadStanza reads one line from the age stream with bufio ReadBytes('\n'); any read failure — most often io.ErrUnexpectedEOF or io.EOF at a truncated stream — is wrapped as 'failed to read line'. The underlying cause is preserved via %w so errors.Is/As work.
Source
Thrown at internal/format/format.go:192
err error
}
func NewStanzaReader(r *bufio.Reader) *StanzaReader {
return &StanzaReader{r: r}
}
func (r *StanzaReader) ReadStanza() (s *Stanza, err error) {
// Read errors are unrecoverable.
if r.err != nil {
return nil, r.err
}
defer func() { r.err = err }()
s = &Stanza{}
line, err := r.r.ReadBytes('\n')
if err != nil {
return nil, fmt.Errorf("failed to read line: %w", err)
}
if !bytes.HasPrefix(line, stanzaPrefix) {
return nil, fmt.Errorf("malformed stanza opening line: %q", line)
}
prefix, args := splitArgs(line)
if prefix != string(stanzaPrefix) || len(args) < 1 {
return nil, fmt.Errorf("malformed stanza: %q", line)
}
s.Type = args[0]
s.Args = args[1:]
for {
line, err := r.r.ReadBytes('\n')
if err != nil {
return nil, fmt.Errorf("failed to read line: %w", err)
}
b, err := DecodeString(strings.TrimSuffix(string(line), "\n"))View on GitHub (pinned to b74dce4cdb)
Solutions
- Check errors.Is(err, io.ErrUnexpectedEOF)/io.EOF: the input is truncated — obtain a complete file
- Verify the input is a real age v1 file and not corrupted or the wrong format
- Re-transfer/re-download the encrypted file and compare sizes/checksums
Example fix
// before
s, err := r.ReadStanza()
if err != nil { return err }
// after
s, err := r.ReadStanza()
if err != nil {
if errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF) {
return fmt.Errorf("truncated age input: %w", err)
}
return err
} Defensive patterns
Strategy: try-catch
Try / catch
s, err := r.ReadStanza()
if err != nil {
switch {
case errors.Is(err, io.ErrUnexpectedEOF), errors.Is(err, io.EOF):
return fmt.Errorf("truncated age input: %w", err)
}
return err
} Prevention
- Verify file integrity (size/checksum) after downloads before decrypting
- Use binary-safe transfers for .age files
- Unwrap with errors.Is to distinguish truncation from format errors
When it happens
Trigger: Parsing an age file/stream that ends mid-stanza, a closed/short pipe, or a network stream cut before the stanza header line arrives; also reading a non-age binary file whose read fails.
Common situations: Truncated downloads of .age files, wrong file passed to age decrypt, pipelines where the producer died early, testing with garbage input in TestParseErrorsDoNotIncludeLine-style tests.
Related errors
- invalid first line: %q
- invalid closing line: %q
- malformed stanza opening line: %q
- malformed stanza: %q
- failed to read OK stanza: %v
AI-assisted analysis of FiloSottile/age@b74dce4cdb (2026-08-31).
Data as JSON: /api/errors/0783030b69946de3.
Report an issue: GitHub.