golang/go · error
archive/tar: missed writing %d bytes
Error message
archive/tar: missed writing %d bytes
What it means
Returned by (*tar.Writer).Flush (writer.go:57) when the current file still has unwritten bytes — tw.curr.logicalRemaining() > 0. Flush is documented to require the current file be fully written first; calling it early (before writing Header.Size bytes) violates that contract.
Source
Thrown at src/archive/tar/writer.go:57
type fileWriter interface {
io.Writer
fileState
ReadFrom(io.Reader) (int64, error)
}
// Flush finishes writing the current file's block padding.
// The current file must be fully written before Flush can be called.
//
// This is unnecessary as the next call to [Writer.WriteHeader] or [Writer.Close]
// will implicitly flush out the file's padding.
func (tw *Writer) Flush() error {
if tw.err != nil {
return tw.err
}
if nb := tw.curr.logicalRemaining(); nb > 0 {
return fmt.Errorf("archive/tar: missed writing %d bytes", nb)
}
if _, tw.err = tw.w.Write(zeroBlock[:tw.pad]); tw.err != nil {
return tw.err
}
tw.pad = 0
return nil
}
// WriteHeader writes hdr and prepares to accept the file's contents.
// The Header.Size determines how many bytes can be written for the next file.
// If the current file is not fully written, then this returns an error.
// This implicitly flushes any padding necessary before writing the header.
func (tw *Writer) WriteHeader(hdr *Header) error {
if err := tw.Flush(); err != nil {
return err
}
tw.hdr = *hdr // Shallow copy of Header
View on GitHub (pinned to b6b368adc5)
Solutions
- Ensure you write exactly hdr.Size bytes after WriteHeader before calling Flush/WriteHeader/Close.
- If the true size is unknown, stream to a buffer/counter first and set Size to the counted length.
- Do not call Flush unless you specifically need block padding mid-stream; rely on WriteHeader/Close implicit flush.
- If a write fails partway, abort the whole archive (the tar is already corrupt).
Example fix
// before
hdr := &tar.Header{Name: "f", Size: 1024, Mode: 0644}
tw.WriteHeader(hdr)
io.CopyN(tw, src, 512) // only half
tw.Flush() // -> missed writing 512 bytes
// after
hdr := &tar.Header{Name: "f", Size: 1024, Mode: 0644}
tw.WriteHeader(hdr)
io.Copy(tw, io.LimitReader(src, 1024)) // exactly Size
tw.Flush() Defensive patterns
Strategy: validation
Validate before calling
// Count content before writing the header so Size is exact.
func writeExact(tw *tar.Writer, name string, r io.Reader) error {
var buf bytes.Buffer
n, _ := io.Copy(&buf, r)
h := &tar.Header{Name: name, Mode: 0644, Size: int64(buf.Len())}
if err := tw.WriteHeader(h); err != nil {
return err
}
_, err := io.CopyN(tw, &buf, n)
return err
} Prevention
- Always write exactly Header.Size bytes before Flush/WriteHeader/Close.
- When size is unknown, buffer-and-count first or use a streaming tar with deferred size patching.
- Avoid calling Flush directly; rely on implicit flush by WriteHeader/Close.
When it happens
Trigger: Calling Writer.Flush (or WriteHeader/Close, which call Flush implicitly) after WriteHeader with a declared Size but before writing exactly Size bytes of content. Also if the writer's content writer short-wrote or the caller stopped early.
Common situations: Declared header Size larger than the actual data streamed (e.g., set Size but io.Copy from a shorter reader); caller returns early from a walk without finishing the file; misuse of Flush as a generic sync point; mismatch between ContentLength and bytes written.
Related errors
- archive/tar: sockets not supported
- archive/tar: unknown file mode %v
- ErrWriteTooLong
- ErrFieldTooLong
- ErrWriteAfterClose
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/0633437ddef709cd.
Report an issue: GitHub.