{"record":{"id":"a06e7365575a4b2c","repo":"GoogleContainerTools/skaffold","slug":"failed-to-read-object-v","errorCode":null,"errorMessage":"failed to read object: %v","messagePattern":"failed to read object: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/skaffold/gcs/client/native.go","lineNumber":326,"sourceCode":"\t\tif err == iterator.Done {\n\t\t\tbreak\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to iterate objects: %v\", err)\n\t\t}\n\n\t\tif attrs.Name != \"\" {\n\t\t\tmatches = append(matches, attrs.Name)\n\t\t}\n\t}\n\treturn matches, nil\n}\n\nfunc (nb nativeBucketHandler) DownloadObject(ctx context.Context, localPath, uri string) error {\n\treader, err := nb.bucket.Object(uri).NewReader(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read object: %v\", err)\n\t}\n\tdefer reader.Close()\n\n\tfile, err := os.Create(localPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create file: %v\", err)\n\t}\n\tdefer file.Close()\n\n\tif _, err := io.Copy(file, reader); err != nil {\n\t\treturn fmt.Errorf(\"failed to copy object to file: %v\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (nb nativeBucketHandler) UploadObject(ctx context.Context, objName string, content *os.File) error {\n\twc := nb.bucket.Object(objName).NewWriter(ctx)","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/GoogleContainerTools/skaffold/blob/a1189de023efc32d4b8e11f395acc678aa555011/pkg/skaffold/gcs/client/native.go#L308-L344","documentation":"DownloadObject wraps errors from creating a GCS object reader (bucket.Object(uri).NewReader). It means the object could not be opened for download — most commonly it does not exist, the caller lacks read permission, or the request failed at the API/network level. The download aborts before any local file is written.","triggerScenarios":"During DownloadRecursive, an object listed earlier was deleted before download (race), the URI encodes an object the account cannot read, or the storage API returns 404/403/5xx when opening the reader.","commonSituations":"CI race where another job overwrites/deletes objects while downloading; bucket with uniform bucket-level access and a service account lacking storage.objects.get; eventual-consistency confusion after a fresh upload; requester-pays bucket without a billing project.","solutions":["Read the wrapped error: 404 means the object vanished or the name is wrong — re-list and retry","Grant the identity roles/storage.objectViewer (storage.objects.get) on the bucket","Retry the DownloadRecursive call on transient 5xx errors","Check requester-pays configuration and set the billing user project if applicable"],"exampleFix":"// before\nbucket.DownloadObject(ctx, localPath, uri) // 404: object deleted mid-download\n// after\nerr := bucket.DownloadObject(ctx, localPath, uri)\nif err != nil {\n    if strings.Contains(err.Error(), \"object doesn't exist\") {\n        err = retryWithBackoff(func() error { return bucket.DownloadObject(ctx, localPath, uri) })\n    }\n}","handlingStrategy":"retry","validationCode":"func checkObjectReadable(ctx context.Context, bucketName, objName string) error {\n\tclient, err := storage.NewClient(ctx)\n\tif err != nil { return err }\n\tdefer client.Close()\n\t_, err = client.Bucket(bucketName).Object(objName).Attrs(ctx)\n\treturn err // pre-flight existence/permission probe\n}\n// optionally probe before downloads, but prefer retry for race-prone listings","typeGuard":null,"tryCatchPattern":"if err := n.DownloadRecursive(ctx, src, dst); err != nil {\n\tif strings.Contains(err.Error(), \"failed to read object\") {\n\t\tif isNotFound(err) || isTransient(err) {\n\t\t\treturn retryBackoff(3, time.Second, func() error {\n\t\t\t\treturn n.DownloadRecursive(ctx, src, dst)\n\t\t\t})\n\t\t}\n\t}\n\treturn err\n}","preventionTips":["Retry downloads when objects may be replaced/deleted concurrently","Ensure storage.objects.get permission for uniform bucket-level access buckets","Avoid downloading immediately after upload of the same object path","Set requester-pays user project if the bucket requires it"],"tags":["gcs","network","permissions","download"],"backgroundTag":"gcs-object-not-found","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"}