GoogleContainerTools/skaffold · error

writing real file %q: %w

Error message

writing real file %q: %w

What it means

This error wraps any failure that occurs while streaming a regular file's contents into a tar archive via io.Copy in addFileToTar. The copy runs through a cancelableWriter that aborts when the context is canceled, so the wrapped error is either an underlying read/write I/O failure or ctx.Err() (e.g. context canceled). Skaffold surfaces it while building tar-based artifacts (CreateTar, CreateMappedTar, CreateTarWithParents).

Source

Thrown at pkg/skaffold/util/tar.go:205

		return err
	}
	if mode.IsRegular() {
		f, err := os.Open(src)
		if err != nil {
			return err
		}
		defer f.Close()

		if ctx.Err() != nil {
			return ctx.Err()
		}

		// Wrap the tar.Writer in a cancelableWriter that checks the context
		cw := &cancelableWriter{w: tw, ctx: ctx}

		// Proceed with copying the file content using the cancelable writer
		if _, err := io.Copy(cw, f); err != nil {
			return fmt.Errorf("writing real file %q: %w", src, err)
		}
	}

	return nil
}

// Code copied from https://github.com/moby/moby/blob/master/pkg/archive/archive_windows.go
func chmodTarEntry(perm os.FileMode) os.FileMode {
	// perm &= 0755 // this 0-ed out tar flags (like link, regular file, directory marker etc.)
	permPart := perm & os.ModePerm
	noPermPart := perm &^ os.ModePerm
	// Add the x bit: make everything +x from windows
	permPart |= 0111
	permPart &= 0755

	return noPermPart | permPart
}

View on GitHub (pinned to a1189de023)

Solutions

  1. Re-run the command; a transient I/O hiccup or intentional Ctrl-C cancel is the most common cause.
  2. Verify the source file still exists, is readable, and is stable (not being rewritten) during archiving.
  3. Check free disk space on the volume receiving the tar output.
  4. If canceled programmatically, extend or remove the context deadline/timeout around the tar operation.

Example fix

// before
err := util.CreateTar(ctx, tmpdir, deps.Dependencies)
// after
if ctx.Err() != nil {
    return fmt.Errorf("context already canceled, skipping tar: %w", ctx.Err())
}
if err := util.CreateTar(ctx, tmpdir, deps.Dependencies); err != nil {
    log.Entry(ctx).Warnf("tar failed (%v); retrying once", err)
    err = util.CreateTar(context.WithoutCancel(ctx), tmpdir, deps.Dependencies)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before archiving
if _, err := os.Stat(src); err != nil {
    return fmt.Errorf("source unreadable: %w", err)
}
if err := ctx.Err(); err != nil {
    return err
}

Try / catch

if err := util.CreateTar(ctx, tmp, deps); err != nil {
    var ctxErr = context.Canceled
    if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
        // user cancel / timeout: treat as expected
        return err
    }
    // transient I/O: retry once
    return util.CreateTar(context.WithoutCancel(ctx), tmp, deps)
}

Prevention

When it happens

Trigger: Calling CreateTar/CreateMappedTar/CreateTarWithParents on a source file that shrinks or becomes unreadable mid-copy, a disk-full or I/O error on the tar writer's destination, or the passed context being canceled while io.Copy is streaming the file bytes.

Common situations: Files deleted or truncated by another process (or a rebuild) while the tar is being assembled; the user hits Ctrl-C so the context cancels partway through copying; out-of-space on the output volume; network filesystems dropping mid-read.

Related errors


AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05). Data as JSON: /api/errors/e76096343db4d9bf. Report an issue: GitHub.