containerd/containerd · error

failed to write file header: %w

Error message

failed to write file header: %w

What it means

After computing the header and writing parent directories, HandleChange writes the tar header with cw.tw.WriteHeader. Any tar writer failure (underlying writer error, write-after-close, out-of-space on the sink) is wrapped with this message so the caller knows header serialization failed rather than file content copy.

Source

Thrown at pkg/archive/tar.go:658

		} else if k == fs.ChangeKindUnmodified {
			// Nothing to write to diff
			return nil
		}

		if capability, err := getxattr(source, "security.capability"); err != nil {
			return fmt.Errorf("failed to get capabilities xattr: %w", err)
		} else if len(capability) > 0 {
			if hdr.PAXRecords == nil {
				hdr.PAXRecords = map[string]string{}
			}
			hdr.PAXRecords[paxSchilyXattr+"security.capability"] = string(capability)
		}

		if err := cw.includeParents(hdr); err != nil {
			return err
		}
		if err := cw.tw.WriteHeader(hdr); err != nil {
			return fmt.Errorf("failed to write file header: %w", err)
		}

		if hdr.Typeflag == tar.TypeReg && hdr.Size > 0 {
			file, err := open(source)
			if err != nil {
				return fmt.Errorf("failed to open path: %v: %w", source, err)
			}
			defer file.Close()

			n, err := copyBuffered(context.TODO(), cw.tw, file)
			if err != nil {
				return fmt.Errorf("failed to copy: %v: %w", source, err)
			}
			if n != hdr.Size {
				return errors.New("short write copying file")
			}
		}

View on GitHub (pinned to 4246446a2b)

Solutions

  1. Check the wrapped inner error from the tar writer
  2. Ensure the destination writer stays open until ChangeWriter.Close completes
  3. Do not call Close concurrently with HandleChange
  4. Check available disk space or downstream transport health

Example fix

// before
pr, pw := io.Pipe()
go func(){ cw.Close(); pw.Close() }() // closes early
// after
go func(){ defer pw.Close(); if err := cw.Close(); err != nil { log.Error(err) } }()
Defensive patterns

Strategy: try-catch

Try / catch

pr, pw := io.Pipe()
done := make(chan error, 1)
go func() {
    defer close(done)
    _, err := io.Copy(consumer, pr)
    if err != nil { pr.CloseWithError(err) } // propagate sink errors upstream
}()
if err := w.HandleChange(kind, path, fi); err != nil {
    return fmt.Errorf("tar header write failed for %s: %w", path, err)
}

Prevention

When it happens

Trigger: tw.WriteHeader returns an error — typically the underlying io.Writer of the tar writer failed (pipe closed, disk full, connection broken), or WriteHeader is invoked on a tar.Writer already closed by a prior error.

Common situations: Consumer of the tar stream closed the pipe early; disk full while streaming to a file; concurrent Close of the ChangeWriter while HandleChange is still processing changes.

Related errors


AI-assisted analysis of containerd/containerd@4246446a2b (2026-09-02). Data as JSON: /api/errors/8976bf291708ec41. Report an issue: GitHub.