{"record":{"id":"fa0ba2cc11aa69e0","repo":"FiloSottile/age","slug":"non-eof-error-reading-after-end-of-encrypted-file","errorCode":null,"errorMessage":"non-EOF error reading after end of encrypted file: %w","messagePattern":"non-EOF error reading after end of encrypted file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/stream/stream.go","lineNumber":105,"sourceCode":"\n\tlast, err := r.readChunk()\n\tif err != nil {\n\t\tr.err = err\n\t\treturn 0, err\n\t}\n\n\tn := copy(p, r.unread)\n\tr.unread = r.unread[n:]\n\n\tif last {\n\t\t// Ensure there is an EOF after the last chunk as expected. In other\n\t\t// words, check for trailing data after a full-length final chunk.\n\t\t// Hopefully, the underlying reader supports returning EOF even if it\n\t\t// had previously returned an EOF to ReadFull.\n\t\tif _, err := io.ReadFull(r.src, make([]byte, 1)); err == nil {\n\t\t\tr.err = errors.New(\"trailing data after end of encrypted file\")\n\t\t} else if err != io.EOF {\n\t\t\tr.err = fmt.Errorf(\"non-EOF error reading after end of encrypted file: %w\", err)\n\t\t} else {\n\t\t\tr.err = io.EOF\n\t\t}\n\t}\n\n\treturn n, nil\n}\n\n// readChunk reads the next chunk of ciphertext from r.src and makes it available\n// in r.unread. last is true if the chunk was marked as the end of the message.\n// readChunk must not be called again after returning a last chunk or an error.\nfunc (r *DecryptReader) readChunk() (last bool, err error) {\n\tif len(r.unread) != 0 {\n\t\tpanic(\"stream: internal error: readChunk called with dirty buffer\")\n\t}\n\n\tin := r.buf[:]\n\tn, err := io.ReadFull(r.src, in)","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/FiloSottile/age/blob/b74dce4cdbe35b5e5f66c06d9612b72f89028758/internal/stream/stream.go#L87-L123","documentation":"After the DecryptReader emits the last marked chunk, it peeks one more byte from the source to confirm the ciphertext ends cleanly. This error means that peek returned a non-EOF, non-nil error, so the reader cannot certify that the encrypted stream terminated correctly. The decrypted data read so far was authenticated, but the underlying source errored while checking for trailing data.","triggerScenarios":"Calling Read on a DecryptReader until the final chunk is consumed; io.ReadFull(src, 1-byte) after the last chunk returns an error other than io.EOF (e.g. an I/O error from a file, network reader, or pipe).","commonSituations":"Reading an encrypted file from a flaky network connection or failing disk; a wrapped reader (e.g. an HTTP body or gzip reader) that surfaces a mid-read error at stream end; a pipe/socket closed abruptly instead of returning EOF.","solutions":["Inspect the wrapped error (%w) to identify the underlying reader failure and fix that source first.","If reading from a network or pipe, ensure the sender closes the stream cleanly so Read returns io.EOF.","Retry the read/transfer if the source is transient (network glitch) rather than the ciphertext being bad.","If the source is a local file, check disk health and file integrity."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"// Go: unwrap to check for a clean EOF vs a source error\nif err != nil && !errors.Is(err, io.EOF) {\n    var srcErr error\n    if errors.As(err, &srcErr) { /* inspect wrapped reader error */ }\n}","tryCatchPattern":"n, err := reader.Read(buf)\nif errors.Is(err, io.EOF) {\n    // clean end\n} else if err != nil {\n    var wrapped error\n    if errors.As(err, &wrapped) {\n        log.Printf(\"source failed while verifying stream end: %v\", wrapped)\n    }\n}","preventionTips":["Read from stable sources (os.File, bytes.Reader) where possible.","Ensure writers close pipes/connections cleanly so EOF is delivered.","Treat non-EOF wrapped errors as source I/O problems, not corruption."],"tags":["stream","io","network","go"],"backgroundTag":"unexpected-io-error","analyzedSha":"b74dce4cdbe35b5e5f66c06d9612b72f89028758","analyzedAt":"2026-08-31T23:59:31.627Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}