argoproj/argo-workflows · error
unable to upload stream to Azure blob %s: %w
Error message
unable to upload stream to Azure blob %s: %w
What it means
SaveStream calls blobClient.UploadStream to write the reader's contents to Azure. If the streaming upload fails (auth, throttling, connection reset mid-stream, invalid blob name), the SDK error is wrapped with this message.
Source
Thrown at workflow/artifacts/azure/azure.go:322
return nil
}
// SaveStream saves an artifact from an io.Reader to Azure Blob Storage
func (azblobDriver *ArtifactDriver) SaveStream(ctx context.Context, reader io.Reader, outputArtifact *wfv1.Artifact) error {
logger := logging.RequireLoggerFromContext(ctx)
logger.WithField("endpoint", outputArtifact.Azure.Endpoint).
WithField("container", outputArtifact.Azure.Container).
WithField("blob", outputArtifact.Azure.Blob).
Info(ctx, "Streaming to Azure Blob Storage")
containerClient, err := azblobDriver.newAzureContainerClient(ctx)
if err != nil {
return fmt.Errorf("unable to create Azure Blob Container client for %s: %w", outputArtifact.Azure.Blob, err)
}
blobClient := containerClient.NewBlockBlobClient(outputArtifact.Azure.Blob)
if _, err = blobClient.UploadStream(ctx, reader, nil); err != nil {
return fmt.Errorf("unable to upload stream to Azure blob %s: %w", outputArtifact.Azure.Blob, err)
}
return nil
}
// PutFile uploads a file to Azure Blob Storage
func PutFile(ctx context.Context, containerClient *container.Client, blobName, path string) error {
blobClient := containerClient.NewBlockBlobClient(blobName)
file, err := os.Open(path)
if err != nil {
return fmt.Errorf("unable to open file %s: %w", path, err)
}
defer func() {
if closeErr := file.Close(); closeErr != nil {
logger := logging.RequireLoggerFromContext(ctx)
logger.WithError(closeErr).Warn(ctx, "unable to close file")
}
}()View on GitHub (pinned to 35bff19146)
Solutions
- Inspect the wrapped Azure error code (AuthorizationFailure, ServerBusy, etc.) and address it.
- Retry the operation; UploadStream errors are often transient network failures.
- Confirm write permissions (Storage Blob Data Contributor) for the key/identity.
- Check storage account firewall/network rules.
- For very large streams, increase timeouts and ensure stable connectivity.
Example fix
// before: no retry around streaming upload err := driver.SaveStream(ctx, reader, artifact) // after: retry transient failures wait.Backoff(... ) // retry SaveStream on 5xx/timeout errors
Defensive patterns
Strategy: retry
Validate before calling
if reader == nil {
return errors.New("nil reader passed to SaveStream")
}
if artifact.Azure.Blob == "" {
return errors.New("blob name is empty")
} Type guard
func isRetryableUploadErr(err error) bool {
var re *azcore.ResponseError
if !errors.As(err, &re) { return false }
return re.StatusCode == 429 || re.StatusCode >= 500 || errors.Is(err, io.ErrUnexpectedEOF)
} Try / catch
err := retry.OnError(wait.Backoff{Steps: 4, Duration: time.Second, Factor: 2},
isRetryableUploadErr, func() error {
return driver.SaveStream(ctx, reader, artifact)
}) Prevention
- Wrap streamed uploads in bounded retries with backoff.
- Increase timeouts for very large streams.
- Confirm write RBAC/keys before long-running stream jobs.
- Watch storage-account throttle metrics (429).
When it happens
Trigger: Uploading an io.Reader (e.g. container logs, large artifacts) when the network drops mid-stream, the account is throttled, credentials lack write permission, or the blob name is invalid.
Common situations: Streaming very large logs over flaky connections; 429 throttling from heavy artifact traffic; container-level firewall blocking; RBAC/key lacking write on the container.
Related errors
- unable to download blob %s: %w
- unable to open stream for blob %s: %w
- unable to upload directory %s to Azure: %w
- unable to upload file %s to Azure: %w
- unable to test if %s is a directory: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/5efe67b92e9c5733.
Report an issue: GitHub.