{"record":{"id":"577863d587681228","repo":"FiloSottile/age","slug":"malformed-stanza-opening-line-q","errorCode":null,"errorMessage":"malformed stanza opening line: %q","messagePattern":"malformed stanza opening line: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/format/format.go","lineNumber":195,"sourceCode":"func NewStanzaReader(r *bufio.Reader) *StanzaReader {\n\treturn &StanzaReader{r: r}\n}\n\nfunc (r *StanzaReader) ReadStanza() (s *Stanza, err error) {\n\t// Read errors are unrecoverable.\n\tif r.err != nil {\n\t\treturn nil, r.err\n\t}\n\tdefer func() { r.err = err }()\n\n\ts = &Stanza{}\n\n\tline, err := r.r.ReadBytes('\\n')\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read line: %w\", err)\n\t}\n\tif !bytes.HasPrefix(line, stanzaPrefix) {\n\t\treturn nil, fmt.Errorf(\"malformed stanza opening line: %q\", line)\n\t}\n\tprefix, args := splitArgs(line)\n\tif prefix != string(stanzaPrefix) || len(args) < 1 {\n\t\treturn nil, fmt.Errorf(\"malformed stanza: %q\", line)\n\t}\n\ts.Type = args[0]\n\ts.Args = args[1:]\n\n\tfor {\n\t\tline, err := r.r.ReadBytes('\\n')\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to read line: %w\", err)\n\t\t}\n\n\t\tb, err := DecodeString(strings.TrimSuffix(string(line), \"\\n\"))\n\t\tif err != nil {\n\t\t\tif bytes.HasPrefix(line, footerPrefix) || bytes.HasPrefix(line, stanzaPrefix) {\n\t\t\t\treturn nil, fmt.Errorf(\"malformed body line %q: stanza ended without a short line\\nnote: this might be a file encrypted with an old beta version of age or rage; use age v1.0.0-beta6 or rage to decrypt it\", line)","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/FiloSottile/age/blob/b74dce4cdbe35b5e5f66c06d9612b72f89028758/internal/format/format.go#L177-L213","documentation":"A stanza must begin with the literal prefix '->'. ReadStanza checks bytes.HasPrefix after reading the line; if the line doesn't start with '->', the stream is not a stanza boundary and parsing stops with the offending line quoted (%q) in the error.","triggerScenarios":"Parse/readStanza encountering a file where a stanza header is expected but the line starts with something else (e.g. '---' footer, 'wrong' MAC line, or random text); feeding a plaintext or foreign-format file to the age parser.","commonSituations":"Decrypting a file that isn't age-format, an encrypted file whose body was modified/reordered, concatenating age files, editors that mangled the header.","solutions":["Confirm the input is an age v1 file produced by age encrypt","Check the file wasn't edited, re-wrapped, or concatenated after encryption","Look at the quoted line in the error to identify where format expectations diverge"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// quick pre-check that the input begins like an age file\nhead, _ := bufio.NewReader(f).Peek(2)\nif string(head) == \"\" { return errors.New(\"empty input\") }","typeGuard":null,"tryCatchPattern":"s, err := r.ReadStanza()\nif err != nil && strings.Contains(err.Error(), \"malformed stanza opening line\") {\n    return fmt.Errorf(\"input is not an age v1 stream: %w\", err)\n}","preventionTips":["Only feed age-encrypt output to the parser; sniff format first if input origin is unknown","Avoid post-encryption edits to encrypted files","Quote/preserve the offending line from the error when reporting bugs"],"tags":["age","format","parsing","malformed-input"],"backgroundTag":"malformed-stanza","analyzedSha":"b74dce4cdbe35b5e5f66c06d9612b72f89028758","analyzedAt":"2026-08-31T23:59:31.627Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}