{"record":{"id":"2ddec723aa235ab0","repo":"FiloSottile/age","slug":"invalid-first-line-q","errorCode":null,"errorMessage":"invalid first line: %q","messagePattern":"invalid first line: %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"armor/armor.go","lineNumber":146,"sourceCode":"\t\treturn io.EOF\n\t}\n\n\tvar removedWhitespace int\n\tfor !r.started {\n\t\tline, err := getLine()\n\t\tif err != nil {\n\t\t\treturn 0, r.setErr(err)\n\t\t}\n\t\t// Ignore leading whitespace.\n\t\tif len(bytes.TrimSpace(line)) == 0 {\n\t\t\tremovedWhitespace += len(line) + 1\n\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\") {","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/FiloSottile/age/blob/b74dce4cdbe35b5e5f66c06d9612b72f89028758/armor/armor.go#L128-L164","documentation":"The age ASCII armor reader requires the very first non-whitespace line of the armored input to be exactly the Header constant (\"-----BEGIN AGE ENCRYPTED FILE-----\"). If the first line differs in any way, Read returns this error, indicating the input is not age-armored data or is corrupt.","triggerScenarios":"Calling Read on an armor.Reader whose underlying stream does not start with the exact header line — e.g. the file is raw (non-armored) age ciphertext, a different armor format (PGP blocks), the header was truncated, or the line has typos/extra characters like CRLF mangling or a UTF-8 BOM before the header.","commonSituations":"Piping output of `age` (unarmored) into an armor reader; opening a file that was edited by a tool adding BOM or changing line endings; confusing armored age files with OpenPGP armored files; copying armor text through systems that rewrap lines or strip characters; wrong file passed to a decryption script.","solutions":["Ensure the input was produced with age's armor option (age -a / armor.NewWriter); plain age output has no armor header","Check the first bytes of the input for a UTF-8 BOM or whitespace/garbage before the header and strip them","Confirm the header reads exactly \"-----BEGIN AGE ENCRYPTED FILE-----\" with no edits, wrapping, or CRLF-only corruption from Windows transfer","Verify you are not feeding a PGP-armored file (\"-----BEGIN PGP MESSAGE-----\"); decrypt it with the proper tool instead","If you must accept both armored and raw input, detect the header before wrapping in armor.NewReader"],"exampleFix":"// before\nf, _ := os.Open(\"file.age\")\nr, _ := armor.NewReader(f) // fails: \"invalid first line\" because file was not armored\n\n// after\nf, _ := os.Open(\"file.age\")\nhead := make([]byte, 6)\nn, _ := io.ReadFull(f, head)\nf.Seek(0, 0)\nvar r io.Reader = f\nif string(head[:n]) == \"-----BEGIN AGE ENCRYPTED FILE-----\" {\n    r = armor.NewReader(f)\n}","handlingStrategy":"validation","validationCode":"func isAgeArmored(data []byte) bool {\n\ts := strings.TrimLeft(string(data), \" \\t\\r\\n\")\n\ts = strings.TrimPrefix(s, \"\\ufeff\") // BOM\n\treturn strings.HasPrefix(s, \"-----BEGIN AGE ENCRYPTED FILE-----\")\n}","typeGuard":null,"tryCatchPattern":"r, err := armor.NewReader(f), then on err containing \"invalid first line\" fall back to treating input as raw age ciphertext:\nif !isAgeArmored(raw) {\n\tout, err := age.Decrypt(bytes.NewReader(raw), identities)\n\t// handle raw path\n}","preventionTips":["Always produce armored files with age -a or armor.NewWriter; never hand-edit the header","Strip UTF-8 BOMs when reading files on Windows","Use binary-safe transfer (scp/rsync with correct flags) instead of copy/paste through editors or email","Detect armor presence before wrapping input in armor.NewReader"],"tags":["armor","parsing","input-format","age"],"backgroundTag":"invalid-armor-header","analyzedSha":"b74dce4cdbe35b5e5f66c06d9612b72f89028758","analyzedAt":"2026-08-31T23:59:31.627Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}