GoogleContainerTools/skaffold · error

failed to download manifests fom GCS: %w

Error message

failed to download manifests fom GCS: %w

What it means

For each valid gs:// path, DownloadFromGCS calls the GCS client's DownloadRecursive; any download failure (bucket missing, object missing, auth error, network error) is wrapped as 'failed to download manifests fom GCS' (note the upstream typo).

Source

Thrown at pkg/skaffold/kubernetes/manifest/gcs.go:53

var GetGCSClient = func() GCSClient {
	return &client.Native{}
}

// DownloadFromGCS downloads all provided manifests from a remote GCS bucket,
// and returns a relative path pointing to the GCS temp dir.
func DownloadFromGCS(manifests []string) (string, error) {
	dir := filepath.Join(ManifestTmpDir, ManifestsFromGCS)
	if err := os.MkdirAll(dir, os.ModePerm); err != nil {
		return "", fmt.Errorf("failed to create the tmp directory: %w", err)
	}
	for _, manifest := range manifests {
		if manifest == "" || !strings.HasPrefix(manifest, gcsPrefix) {
			return "", fmt.Errorf("%v is not a valid GCS path", manifest)
		}
		gcs := GetGCSClient()
		if err := gcs.DownloadRecursive(context.Background(), manifest, dir); err != nil {
			return "", fmt.Errorf("failed to download manifests fom GCS: %w", err)
		}
	}
	return ManifestTmpDir, nil
}

View on GitHub (pinned to a1189de023)

Solutions

  1. Verify the gs:// bucket and object path exist with 'gsutil ls gs://bucket/path'
  2. Set up credentials: 'gcloud auth application-default login' locally, or attach a service account with Storage Object Viewer in CI
  3. Check the wrapped cause (%w) to distinguish 403 auth vs 404 not-found vs network errors
  4. Retry on transient network errors; fix VPC/DNS/firewall if storage.googleapis.com is unreachable

Example fix

// before: no credentials in CI
gs://my-private-bucket/manifests  -> 403
// after: provide credentials
echo "$GCP_SA_KEY" > /tmp/sa.json
export GOOGLE_APPLICATION_CREDENTIALS=/tmp/sa.json
Defensive patterns

Strategy: retry

Validate before calling

import "os/exec"
func gcsPathExists(gsURI string) bool {
  return exec.Command("gsutil", "ls", gsURI).Run() == nil
}
// also verify credentials: os.Getenv("GOOGLE_APPLICATION_CREDENTIALS") or ADC present

Try / catch

path, err := manifest.DownloadFromGCS(manifests)
if err != nil && strings.Contains(err.Error(), "failed to download manifests fom GCS") {
  // transient network errors: retry with backoff; auth/notfound: surface cause
  for i := 0; i < 3; i++ {
    time.Sleep(time.Duration(1<<i) * time.Second)
    if path, err = manifest.DownloadFromGCS(manifests); err == nil { break }
  }
}

Prevention

When it happens

Trigger: Calling manifest.DownloadFromGCS when gcs.DownloadRecursive fails: nonexistent bucket/object, 401/403 from missing or expired credentials (GOOGLE_APPLICATION_CREDENTIALS), or network/DNS failure contacting storage.googleapis.com.

Common situations: Private buckets without application-default credentials ('gcloud auth application-default login'), wrong bucket name/region, CI runners without the storage.objects.get permission on the service account, or air-gapped environments without GCS reachability.

Related errors


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