k3s-io/k3s · error

error writing to %s: %v

Error message

error writing to %s: %v

What it means

Returned when writing an extracted regular file fails: the destination file was opened with O_RDWR|O_CREATE|O_TRUNC and either io.Copy(wf, tr) or a deferred wf.Close() returned an error (Close is promoted to the returned error if Copy succeeded). Typical errno causes are ENOSPC (disk or quota full), EACCES/EPERM (permissions, read-only mount), EDQUOT, or EIO on the underlying device.

Source

Thrown at pkg/untar/untar.go:88

			// beforehand. Thus, don't check for errors; the next
			// write will fail with the same error.
			dir := filepath.Dir(abs)
			if !madeDir[dir] {
				if err := os.MkdirAll(filepath.Dir(abs), 0755); err != nil {
					return err
				}
				madeDir[dir] = true
			}
			wf, err := os.OpenFile(abs, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode.Perm())
			if err != nil {
				return err
			}
			n, err := io.Copy(wf, tr)
			if closeErr := wf.Close(); closeErr != nil && err == nil {
				err = closeErr
			}
			if err != nil {
				return fmt.Errorf("error writing to %s: %v", abs, err)
			}
			if n != f.Size {
				return fmt.Errorf("only wrote %d bytes to %s; expected %d", n, abs, f.Size)
			}
			modTime := f.ModTime
			if modTime.After(t0) {
				// Clamp modtimes at system time. See
				// golang.org/issue/19062 when clock on
				// buildlet was behind the gitmirror server
				// doing the git-archive.
				modTime = t0
			}
			if !modTime.IsZero() {
				if err := os.Chtimes(abs, modTime, modTime); err != nil && !loggedChtimesError {
					// benign error. Gerrit doesn't even set the
					// modtime in these, and we don't end up relying
					// on it anywhere (the gomote push command relies
					// on digests only), so this is a little pointless

View on GitHub (pinned to 6ba341e396)

Solutions

  1. Check free space and inodes on the destination: df -h <dir> and df -i <dir>
  2. Verify writability as the same user: touch <dir>/.wtest && rm <dir>/.wtest
  3. Fix mount options or ownership if the volume is read-only or permission-denied
  4. If ENOSPC, prune old data/images or enlarge the volume, then retry the extraction
Defensive patterns

Strategy: validation

Validate before calling

func CanExtractInto(dir string, needBytes int64) error {
	var st syscall.Statfs_t
	if err := syscall.Statfs(dir, &st); err != nil {
		return err
	}
	if int64(st.Bavail)*int64(st.Bsize) < needBytes {
		return fmt.Errorf("insufficient space in %s: need %d bytes", dir, needBytes)
	}
	f, err := os.CreateTemp(dir, ".probe-*")
	if err != nil {
		return fmt.Errorf("destination not writable: %w", err)
	}
	return os.Remove(f.Name())
}

Try / catch

if err := untar.Untar(r, dir); err != nil {
	var errno syscall.Errno
	if errors.As(err, &errno) && (errno == syscall.ENOSPC || errno == syscall.EDQUOT) {
		// free space / raise quota, then restart extraction from a clean dir
	}
	return err
}

Prevention

When it happens

Trigger: untar.Untar into a directory on a full filesystem or one with a quota; destination on a read-only mount; running as a uid without write permission on the target path; disk I/O errors during extraction.

Common situations: Airgap/import workflows extracting into a small /var/lib or tmpfs that filled up after downloading the tarball; containers with read-only volumes or fsGroup/uid mismatches; long-lived nodes whose disk filled from old images or logs.

Related errors


AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15). Data as JSON: /api/errors/ed1e64bdd340cd79. Report an issue: GitHub.