GoogleContainerTools/skaffold · error

copy file(s) with %s failed: %w

Error message

copy file(s) with %s failed: %w

What it means

Copy runs the external `gsutil` binary (GsutilExec) with `cp` arguments to copy files to/from GCS and wraps any failure from util.RunCmdOut. Because it shells out to gsutil, the error usually reflects gsutil's own failure — missing binary, bad arguments, authentication problems, or the source/destination not existing. The wrapped error carries gsutil's stderr output for diagnosis.

Source

Thrown at pkg/skaffold/gcs/gsutil.go:62

type gsutil struct{}

// NewGsutil returns a gsutil client.
func NewGsutil() Gsutil {
	return &gsutil{}
}

// Copy calls `gcloud storage cp [--recursive] <source_url> <destination_url>
func (g *gsutil) Copy(ctx context.Context, src, dst string, recursive bool) error {
	args := []string{"storage", "cp"}
	if recursive {
		args = append(args, "--recursive")
	}
	args = append(args, src, dst)
	cmd := exec.CommandContext(ctx, GsutilExec, args...)
	out, err := util.RunCmdOut(ctx, cmd)
	if err != nil {
		return fmt.Errorf("copy file(s) with %s failed: %w", GsutilExec, err)
	}
	log.Entry(ctx).Info(out)
	return nil
}

// GetGCSClient returns a GCS client that uses Client libraries.
var GetGCSClient = func() gscClient {
	return &client.Native{}
}

type gscClient interface {
	// Downloads the content that match the given src uri and subfolders.
	DownloadRecursive(ctx context.Context, src, dst string) error
}

// SyncObjects syncs the target Google Cloud Storage objects with skaffold's local cache and returns the local path to the objects.
func SyncObjects(ctx context.Context, g latest.GoogleCloudStorageInfo, opts config.SkaffoldOptions) (string, error) {
	remoteCacheDir, err := config.GetRemoteCacheDir(opts)

View on GitHub (pinned to a1189de023)

Solutions

  1. Verify gsutil is installed and on PATH: `which gsutil` or install Google Cloud SDK
  2. Run the same gsutil cp command manually to see the raw error
  3. Re-authenticate: `gcloud auth login` or `gcloud auth activate-service-account --key-file=...`
  4. Check that the src path and gs:// dst exist and are correctly formatted
  5. Confirm network/proxy access to storage.googleapis.com from the environment

Example fix

// before
err := gcs.Copy(ctx, opts, src, dst)
// after
if _, err := exec.LookPath(gcs.GsutilExec); err != nil {
	log.Fatalf("gsutil not found; install Google Cloud SDK: %v", err)
}
err := gcs.Copy(ctx, opts, src, dst)
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := exec.LookPath("gsutil"); err != nil {
	return fmt.Errorf("gsutil not installed: %w", err)
}
if !strings.HasPrefix(dst, "gs://") {
	return fmt.Errorf("destination must be a gs:// URL: %q", dst)
}
if _, err := os.Stat(src); err != nil {
	return fmt.Errorf("source missing: %w", err)
}

Type guard

func isGsutilNotFoundError(err error) bool {
	return err != nil && strings.Contains(err.Error(), "CommandException") && strings.Contains(err.Error(), "No such file or directory")
}

Try / catch

if err := gcs.Copy(ctx, opts, src, dst); err != nil {
	if errors.Is(err, exec.ErrNotFound) || strings.Contains(err.Error(), "executable file not found") {
		log.Fatal("install Google Cloud SDK (gsutil) first")
	}
	return fmt.Errorf("gcs copy failed: %w", err)
}

Prevention

When it happens

Trigger: Calling gcs.Copy when the gsutil executable is not on PATH, the source path or destination URL is wrong or nonexistent, credentials are invalid (run `gcloud auth login`), or gsutil exits nonzero for network/API reasons.

Common situations: gsutil not installed (Cloud SDK missing) on CI machines; GCS URLs mistyped (gs:// prefix forgotten); service account not activated (`gcloud auth activate-service-account` skipped); copying a nonexistent local file with --recursive misconfigured.

Related errors


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