{"record":{"id":"aef62fcbf70bbba2","repo":"FiloSottile/age","slug":"encrypted-size-too-small-d","errorCode":null,"errorMessage":"encrypted size too small: %d","messagePattern":"encrypted size too small: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/inspect/inspect.go","lineNumber":122,"sourceCode":"\tdone  bool\n}\n\nfunc (tr *trackReader) Read(p []byte) (int, error) {\n\tif tr.done {\n\t\treturn 0, io.EOF\n\t}\n\tn, err := tr.r.Read(p)\n\ttr.count += int64(n)\n\tif err == io.EOF {\n\t\ttr.done = true\n\t}\n\treturn n, err\n}\n\nfunc streamOverhead(payloadSize int64) (int64, error) {\n\tconst streamNonceSize = 16\n\tif payloadSize < streamNonceSize {\n\t\treturn 0, fmt.Errorf(\"encrypted size too small: %d\", payloadSize)\n\t}\n\tencryptedSize := payloadSize - streamNonceSize\n\tplaintextSize, err := stream.PlaintextSize(encryptedSize)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn payloadSize - plaintextSize, nil\n}\n","sourceCodeStart":104,"sourceCodeEnd":131,"githubUrl":"https://github.com/FiloSottile/age/blob/b74dce4cdbe35b5e5f66c06d9612b72f89028758/internal/inspect/inspect.go#L104-L131","documentation":"streamOverhead requires at least the 16-byte stream nonce at the end of the encrypted payload before subtracting it and applying stream.PlaintextSize. A payload smaller than 16 bytes cannot have been produced by age's STREAM encryption, so the size is rejected.","triggerScenarios":"inspect.Inspect passes fileSize - data.Sizes.Header < 16 to streamOverhead — the file is nearly empty after the header, or the reported size is wrong.","commonSituations":"Empty or 0-byte payload files; truncated encrypted files; callers passing an incorrect fileSize (e.g., header-only size, or compressed size of an outer archive); fuzz/corpus inputs.","solutions":["Check the input file: a valid age file's payload is at least 16 bytes; empty plaintext still yields a nonce plus framed data","Re-encrypt or re-download the file if truncated","Pass the correct fileSize (or -1) to Inspect instead of a miscomputed value","Treat sub-16-byte payloads as corrupt input and reject them at the caller"],"exampleFix":"// before\nn, _ := f.Seek(0, io.SeekEnd) // n from a compressed outer file\n// after\nf.Seek(0, io.SeekStart)\nst, _ := f.Stat()\nif st.Size() < 200 { return fmt.Errorf(\"too small to be an age file: %d\", st.Size()) }\ninspect.Inspect(f, st.Size())","handlingStrategy":"validation","validationCode":"st, _ := f.Stat()\nif st.Size() < 200 { // header + 16-byte nonce minimum\n    return fmt.Errorf(\"not a valid age file: %d bytes\", st.Size())\n}","typeGuard":"n/a — plain error value; detect via strings.Contains(err.Error(), \"encrypted size too small\")","tryCatchPattern":"data, err := inspect.Inspect(f, size)\nif err != nil {\n    if strings.Contains(err.Error(), \"encrypted size too small\") {\n        return fmt.Errorf(\"corrupt or truncated age file\")\n    }\n    return err\n}","preventionTips":["Enforce a minimum plausible age file size before inspecting or decrypting","Never pass computed/outer sizes to Inspect; use the actual file size or -1","Treat empty-payload encryptions as invalid input at the caller"],"tags":["inspect","validation","stream-framing","size-validation"],"backgroundTag":"payload-too-small","analyzedSha":"b74dce4cdbe35b5e5f66c06d9612b72f89028758","analyzedAt":"2026-08-31T23:59:31.627Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}