{"record":{"id":"b7b4c2199e7d4b88","repo":"FiloSottile/age","slug":"empty-line-in-armored-data","errorCode":null,"errorMessage":"empty line in armored data","messagePattern":"empty line in armored data","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"armor/armor.go","lineNumber":158,"sourceCode":"\t\t\tif removedWhitespace > maxWhitespace {\n\t\t\t\treturn 0, r.setErr(errors.New(\"too much leading whitespace\"))\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif string(line) != Header {\n\t\t\treturn 0, r.setErr(fmt.Errorf(\"invalid first line: %q\", line))\n\t\t}\n\t\tr.started = true\n\t}\n\tline, err := getLine()\n\tif err != nil {\n\t\treturn 0, r.setErr(err)\n\t}\n\tif string(line) == Footer {\n\t\treturn 0, r.setErr(drainTrailing())\n\t}\n\tif len(line) == 0 {\n\t\treturn 0, r.setErr(errors.New(\"empty line in armored data\"))\n\t}\n\tif len(line) > format.ColumnsPerLine {\n\t\treturn 0, r.setErr(errors.New(\"column limit exceeded\"))\n\t}\n\t// Reject newline characters ignored by base64.Decode.\n\tif bytes.ContainsAny(line, \"\\n\\r\") {\n\t\treturn 0, r.setErr(errors.New(\"unexpected newline character\"))\n\t}\n\tr.unread = r.buf[:]\n\tn, err := base64.StdEncoding.Strict().Decode(r.unread, line)\n\tif err != nil {\n\t\treturn 0, r.setErr(err)\n\t}\n\tr.unread = r.unread[:n]\n\n\tif n < format.BytesPerLine {\n\t\tline, err := getLine()\n\t\tif err != nil {","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/FiloSottile/age/blob/b74dce4cdbe35b5e5f66c06d9612b72f89028758/armor/armor.go#L140-L176","documentation":"Inside the armored body, each line must be a non-empty base64 line. An empty line between the header and footer is structurally invalid, so the reader reports this error rather than skipping it, keeping the armor format strict and unambiguous.","triggerScenarios":"Reading an armored file whose payload contains a blank line — typically from editors inserting blank lines, mail clients reformatting, or manual edits to the armored data.","commonSituations":"Pasting armor through email clients that mangle line structure, formatting tools that insert blank lines at column boundaries, or diff/merge artifacts leaving an empty line in the base64 body.","solutions":["Remove the blank line(s) from the armored body so the payload is contiguous 64-column base64 lines.","Regenerate the armored file from the original encrypted payload.","Verify with a text editor that the body has no empty lines between BEGIN and END."],"exampleFix":"// before\n-----BEGIN AGE ENCRYPTED FILE-----\nYWJj...\n\nZGVm...\n-----END AGE ENCRYPTED FILE-----\n// after\n-----BEGIN AGE ENCRYPTED FILE-----\nYWJj...\nZGVm...\n-----END AGE ENCRYPTED FILE-----","handlingStrategy":"validation","validationCode":"// Reject blank lines inside the armor body before decrypting\nfunc validateArmorBody(data []byte) error {\n    inBody := false\n    for _, l := range bytes.Split(data, []byte('\\n')) {\n        s := strings.TrimSpace(string(l))\n        if strings.HasPrefix(s, \"-----BEGIN\") {\n            inBody = true\n            continue\n        }\n        if strings.HasPrefix(s, \"-----END\") {\n            return nil\n        }\n        if inBody && s == \"\" {\n            return errors.New(\"empty line in armored data\")\n        }\n    }\n    return errors.New(\"no footer\")\n}","typeGuard":null,"tryCatchPattern":"_, err := io.ReadAll(armor.NewReader(f))\nif err != nil && err.Error() == \"empty line in armored data\" {\n    // remove blank lines from the armor body and retry\n}","preventionTips":["Keep the armor body contiguous with no blank lines.","Disable editors/tools that reformat or insert blank lines in payload files.","Regenerate the armored file rather than repairing it by hand when unsure."],"tags":["go","age","armor","reader","malformed-input"],"backgroundTag":"malformed-armored-file","analyzedSha":"b74dce4cdbe35b5e5f66c06d9612b72f89028758","analyzedAt":"2026-08-31T23:59:31.627Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}