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
- Verify gsutil is installed and on PATH: `which gsutil` or install Google Cloud SDK
- Run the same gsutil cp command manually to see the raw error
- Re-authenticate: `gcloud auth login` or `gcloud auth activate-service-account --key-file=...`
- Check that the src path and gs:// dst exist and are correctly formatted
- 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
- Install Google Cloud SDK in all environments (CI images) where skaffold uses the gsutil path
- Always use gs:// URLs, not https URLs, for GCS arguments
- Run `gcloud auth login` / activate-service-account before invoking Copy
- Prefer the native client handler over gsutil where possible to avoid external-binary failures
- Manually run the gsutil command to confirm credentials and paths work before automation
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
- error closing GCS writer: %w
- failed determining remote cache directory: %w
- failed determining Google Cloud Storage remote cache directo
- uploading sources to google storage: %w
- bucket name is empty
AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05).
Data as JSON: /api/errors/51987ba2f58a9046.
Report an issue: GitHub.