argoproj/argo-workflows · error
unable to upload file %s to Azure: %w
Error message
unable to upload file %s to Azure: %w
What it means
Fired in ArtifactDriver.Save while uploading a single file to Azure Blob Storage: PutFile (or the preceding client/dir logic) failed and the error is wrapped with the local path. Indicates Azure-side rejection, auth, or network trouble during artifact save.
Source
Thrown at workflow/artifacts/azure/azure.go:300
isDir, err := file.IsDirectory(path)
if err != nil {
return fmt.Errorf("failed to test if %s is a directory: %w", path, err)
}
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)
}
if isDir {
err := PutDirectory(ctx, containerClient, outputArtifact.Azure.Blob, path)
if err != nil {
return fmt.Errorf("unable to upload directory %s to Azure: %w", path, err)
}
} else {
err := PutFile(ctx, containerClient, outputArtifact.Azure.Blob, path)
if err != nil {
return fmt.Errorf("unable to upload file %s to Azure: %w", path, err)
}
}
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)
}View on GitHub (pinned to 35bff19146)
Solutions
- Read the wrapped inner error to distinguish local open failure vs Azure upload failure.
- If local: fix permissions/existence of the artifact path.
- If Azure: check credentials, retries, and blob size limits; split large files.
- Verify container-level write permissions for the account key.
- Retry on transient network/storage errors.
Example fix
// before: unreadable file saved as artifact cmd: [sh, -c, "umask 077; generate > /work/out.txt"] // after: ensure readable by executor user cmd: [sh, -c, "generate > /work/out.txt && chmod 644 /work/out.txt"]
Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Stat(path)
if err != nil {
return fmt.Errorf("artifact file missing: %w", err)
}
if info.Size() > 195*1024*1024*1024 {
return errors.New("file exceeds Azure block blob limit")
} Type guard
func isUploadErr(err error) bool {
return errors.As(err, new(*azcore.ResponseError))
} Try / catch
err := driver.Save(ctx, path, artifact)
if err != nil && strings.Contains(err.Error(), "unable to upload file") {
var re *azcore.ResponseError
if errors.As(errors.Unwrap(err), &re) && re.StatusCode >= 500 {
// retry with backoff
}
return err
} Prevention
- Ensure artifact files are readable by the executor user (chmod 644).
- Keep files under the Azure block blob size limit.
- Don't delete/move artifact files before save completes.
- Retry transient 5xx upload errors.
When it happens
Trigger: Saving a file artifact when os.Open fails (permission, disappeared mid-run) or blobClient.UploadFile fails (auth, network, quota, oversized blob).
Common situations: File deleted between generation and save; read-permission problems for the emissary user; single blob exceeding 195GB block-blob limit; transient network errors.
Related errors
- unable to upload directory %s to Azure: %w
- unable to open stream for blob %s: %w
- unable to test if blob %s is a directory: %w
- unable to open blob stream for %s: %w
- unable to upload stream to Azure blob %s: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/65c435313377d0f4.
Report an issue: GitHub.