golang/go · error
errWriteHole
errWriteHole
Error message
archive/tar: write non-NUL byte in sparse hole
What it means
errWriteHole (unexported) is returned by the writer when a non-NUL byte is written into a sparse hole region. Sparse holes are stored as zero gaps; writing real data there is a logic error because the hole has no allocated dense bytes. The zeroWriter only accepts NUL (0x00) bytes and rejects anything else.
Source
Thrown at src/archive/tar/common.go:41
"strings"
"time"
)
// BUG: Use of the Uid and Gid fields in Header could overflow on 32-bit
// architectures. If a large value is encountered when decoding, the result
// stored in Header will be the truncated version.
var tarinsecurepath = godebug.New("tarinsecurepath")
var (
ErrHeader = errors.New("archive/tar: invalid tar header")
ErrWriteTooLong = errors.New("archive/tar: write too long")
ErrFieldTooLong = errors.New("archive/tar: header field too long")
ErrWriteAfterClose = errors.New("archive/tar: write after close")
ErrInsecurePath = errors.New("archive/tar: insecure file path")
errMissData = errors.New("archive/tar: sparse file references non-existent data")
errUnrefData = errors.New("archive/tar: sparse file contains unreferenced data")
errWriteHole = errors.New("archive/tar: write non-NUL byte in sparse hole")
errSparseTooLong = errors.New("archive/tar: sparse map too long")
)
type headerError []string
func (he headerError) Error() string {
const prefix = "archive/tar: cannot encode header"
var ss []string
for _, s := range he {
if s != "" {
ss = append(ss, s)
}
}
if len(ss) == 0 {
return prefix
}
return fmt.Sprintf("%s: %v", prefix, strings.Join(ss, "; and "))
}View on GitHub (pinned to b6b368adc5)
Solutions
- Align writes with the sparse map: write only into declared data fragments, and write NUL bytes (or nothing) into holes.
- When you have a fully materialized file, do not declare sparse holes at all — use a normal regular file header.
- Pre-zero any buffer used for padding: bytes.Fill(buf, 0) before writing it into hole regions.
- If you genuinely need to write data where a hole was, fix the Sparses map first so the region becomes a data fragment.
Example fix
// before
hdr := &tar.Header{Size: 10, Sparses: []tar.SparseEntry{{Offset: 5, NumBytes: 5}}}
tw.WriteHeader(hdr)
tw.Write([]byte("abcdefghij")) // bytes 0-4 are a hole, throws errWriteHole
// after
hdr := &tar.Header{Size: 10, Sparses: []tar.SparseEntry{{Offset: 5, NumBytes: 5}}}
tw.WriteHeader(hdr)
tw.Write(bytes.Repeat([]byte{0}, 5)) // hole region, NUL ok
tw.Write([]byte("fghij")) // data fragment Defensive patterns
Strategy: validation
Validate before calling
// Before writing, ensure your buffer offsets align with sparse data fragments,
// and that any hole-region bytes are zero.
for _, b := range buf {
if b != 0 { /* writing into a hole: re-check sparse map */ }
} Type guard
func isAllZero(b []byte) bool { for _, x := range b { if x != 0 { return false } }; return true } Prevention
- Align writes precisely with the sparse data fragments; never write data into hole regions.
- Pre-zero any padding buffers before writing them.
- Prefer non-sparse headers unless you genuinely have holes.
When it happens
Trigger: Calling Write on a tar entry that has sparse holes, and pushing a buffer that overlaps a hole region with non-zero bytes; mis-sequencing writes so data lands at an offset the sparse map designates as a hole.
Common situations: Manually writing a sparse file without aligning writes to the declared fragment offsets; buggy code that interleaves data and padding without zeroing the padding; using io.Copy into a sparse-aware writer when the source contains unexpected non-zero bytes in what should be holes.
Related errors
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/ed52bab2e5275b61.
Report an issue: GitHub.