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
- Verify the gs:// bucket and object path exist with 'gsutil ls gs://bucket/path'
- Set up credentials: 'gcloud auth application-default login' locally, or attach a service account with Storage Object Viewer in CI
- Check the wrapped cause (%w) to distinguish 403 auth vs 404 not-found vs network errors
- 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
- Set up ADC locally ('gcloud auth application-default login') and workload identity/service-account keys in CI
- Grant the running identity storage.objects.get/list on the bucket
- Verify bucket paths with 'gsutil ls' before automating downloads
- Add retry with backoff for transient network failures; check egress/DNS in restricted environments
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
- failed to read object: %v
- failed to copy object to file: %v
- %s %q: %w
- failed to iterate objects: %v
- failed to create file: %v
AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05).
Data as JSON: /api/errors/871e27720fed094b.
Report an issue: GitHub.