{"record":{"id":"5e1779bd428eda7b","repo":"GoogleContainerTools/skaffold","slug":"failed-to-cache-google-cloud-storage-objects-from","errorCode":null,"errorMessage":"failed to cache Google Cloud Storage objects from %q: %w","messagePattern":"failed to cache Google Cloud Storage objects from %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/skaffold/gcs/gsutil.go","lineNumber":115,"sourceCode":"\t\t}\n\t\t// The subdirectory needs to exist to work with gsutil.\n\t\tif err := os.MkdirAll(cacheDir, 0700); err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"failed creating Google Cloud Storage cache directory for %q: %w\", g.Source, err)\n\t\t}\n\t} else {\n\t\t// If sync property is false then skip fetching latest object from remote storage.\n\t\tif g.Sync != nil && !*g.Sync {\n\t\t\treturn cacheDir, nil\n\t\t}\n\t\t// If sync is turned off via flag `--sync-remote-cache` then skip fetching latest object from remote storage.\n\t\tif opts.SyncRemoteCache.FetchDisabled() {\n\t\t\treturn cacheDir, nil\n\t\t}\n\t}\n\n\tgcs := GetGCSClient()\n\tif err := gcs.DownloadRecursive(ctx, g.Source, cacheDir); err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to cache Google Cloud Storage objects from %q: %w\", g.Source, err)\n\t}\n\treturn cacheDir, nil\n}\n\n// getPerSourceDir returns the directory used per Google Cloud Storage source. Directory is a hash of the source provided.\nfunc getPerSourceDir(g latest.GoogleCloudStorageInfo) (string, error) {\n\tinputs := []string{g.Source}\n\thasher := sha256.New()\n\tenc := json.NewEncoder(hasher)\n\tif err := enc.Encode(inputs); err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn base64.URLEncoding.EncodeToString(hasher.Sum(nil))[:32], nil\n}\n\n// syncDisabledErr returns error to use when remote sync is turned off by the user and the Google Cloud Storage object doesn't exist inside the cache directory.\nfunc syncDisabledErr(g latest.GoogleCloudStorageInfo, cacheDir string) error {","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/GoogleContainerTools/skaffold/blob/a1189de023efc32d4b8e11f395acc678aa555011/pkg/skaffold/gcs/gsutil.go#L97-L133","documentation":"After the per-source cache directory is prepared, SyncObjects downloads all objects from the configured GCS source into it via gcs.DownloadRecursive (the native GCS client). If that download fails, the client's error is wrapped with this message. It means the remote GCS objects could not be fetched and cached locally, so the build/deploy depending on them cannot proceed.","triggerScenarios":"Calling SyncObjects/cacheGCSObject where gcs.DownloadRecursive(ctx, g.Source, cacheDir) fails: source URI is wrong/empty, bucket doesn't exist, no authenticated GCP credentials, no access to the bucket, or network unavailable.","commonSituations":"Typo in the gs:// source URI in the skaffold config; gcloud/application-default credentials missing or expired (CI without Workload Identity/service-account key); insufficient IAM on the bucket; corporate proxy blocking storage.googleapis.com; deleted bucket.","solutions":["Verify the gs:// source URI in your skaffold config is correct and the bucket/prefix still exists (gsutil ls gs://<bucket>).","Authenticate with GCP: gcloud auth application-default login locally, or configure a service account/Workload Identity in CI, and confirm the account has storage.objects.get/list on the bucket.","Run a manual download (gcloud storage cp -r gs://<source> <dir>) to reproduce and see the raw client error.","Check network/proxy access to storage.googleapis.com and retry; populate the cache manually if sync is disabled."],"exampleFix":"// before\nsync:\n  source: gs://my-bucket/manifests   # bucket deleted\n// after\ngcloud storage ls gs://my-bucket/    # verify bucket exists first\nsync:\n  source: gs://my-correct-bucket/manifests","handlingStrategy":"try-catch","validationCode":"// before invoking skaffold, verify source and access\ngcloud storage ls gs://my-bucket/manifests >/dev/null 2>&1 || \\\n  echo \"GCS source missing or no access; check URI and credentials\"\ngcloud auth application-default print-access-token >/dev/null 2>&1 || \\\n  echo \"No valid GCP credentials\"","typeGuard":"func isGCSErrNotFound(err error) bool {\n    var gerr *googleapi.Error\n    return errors.As(err, &gerr) && gerr.Code == 404\n}","tryCatchPattern":"cacheDir, err := gcs.SyncObjects(ctx, gcsInfo, opts)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to cache Google Cloud Storage objects\") {\n        log.Warnf(\"GCS fetch failed; verify `gcloud storage ls %s` and credentials: %v\", gcsInfo.Source, err)\n        return useManuallyPopulatedCache() // fallback path\n    }\n    return err\n}","preventionTips":["Lint skaffold configs so gs:// sources are validated (bucket exists, prefix non-empty) before runs.","Authenticate in CI with Workload Identity or a service-account key that has storage.objects.get/list on the bucket.","Pre-populate the cache and set sync: false for immutable artifacts to avoid repeated network fetches.","Set sync-remote-cache=missing to tolerate offline runs when the cache is already warm."],"tags":["gcs","network","authentication","cache"],"backgroundTag":"gcs-download-failed","analyzedSha":"a1189de023efc32d4b8e11f395acc678aa555011","analyzedAt":"2026-09-05T12:09:27.064Z","contentChangedAt":"2026-09-05T12:09:27.064Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}