GoogleContainerTools/skaffold · error
failed to read object: %v
Error message
failed to read object: %v
What it means
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.
Source
Thrown at pkg/skaffold/gcs/client/native.go:326
if err == iterator.Done {
break
}
if err != nil {
return nil, fmt.Errorf("failed to iterate objects: %v", err)
}
if attrs.Name != "" {
matches = append(matches, attrs.Name)
}
}
return matches, nil
}
func (nb nativeBucketHandler) DownloadObject(ctx context.Context, localPath, uri string) error {
reader, err := nb.bucket.Object(uri).NewReader(ctx)
if err != nil {
return fmt.Errorf("failed to read object: %v", err)
}
defer reader.Close()
file, err := os.Create(localPath)
if err != nil {
return fmt.Errorf("failed to create file: %v", err)
}
defer file.Close()
if _, err := io.Copy(file, reader); err != nil {
return fmt.Errorf("failed to copy object to file: %v", err)
}
return nil
}
func (nb nativeBucketHandler) UploadObject(ctx context.Context, objName string, content *os.File) error {
wc := nb.bucket.Object(objName).NewWriter(ctx)View on GitHub (pinned to a1189de023)
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
Example fix
// before
bucket.DownloadObject(ctx, localPath, uri) // 404: object deleted mid-download
// after
err := bucket.DownloadObject(ctx, localPath, uri)
if err != nil {
if strings.Contains(err.Error(), "object doesn't exist") {
err = retryWithBackoff(func() error { return bucket.DownloadObject(ctx, localPath, uri) })
}
} Defensive patterns
Strategy: retry
Validate before calling
func checkObjectReadable(ctx context.Context, bucketName, objName string) error {
client, err := storage.NewClient(ctx)
if err != nil { return err }
defer client.Close()
_, err = client.Bucket(bucketName).Object(objName).Attrs(ctx)
return err // pre-flight existence/permission probe
}
// optionally probe before downloads, but prefer retry for race-prone listings Try / catch
if err := n.DownloadRecursive(ctx, src, dst); err != nil {
if strings.Contains(err.Error(), "failed to read object") {
if isNotFound(err) || isTransient(err) {
return retryBackoff(3, time.Second, func() error {
return n.DownloadRecursive(ctx, src, dst)
})
}
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- failed to iterate objects: %v
- failed to create file: %v
- failed to copy object to file: %v
- failed to download manifests fom GCS: %w
- DEPLOY_CLOUD_RUN_GET_SERVICE_ERR
AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05).
Data as JSON: /api/errors/a06e7365575a4b2c.
Report an issue: GitHub.