argoproj/argo-workflows · error
failed to put file: %w
Error message
failed to put file: %w
What it means
Wraps a failure from the Minio client PutFile call when saving a single-file S3 artifact. Argo's executor retries transient S3 errors (throttling, network blips); when the error is non-transient or retries are exhausted, this wrapper is returned so artifact saving fails the node. The %w wrapping preserves the underlying Minio/S3 error cause.
Source
Thrown at workflow/artifacts/s3/s3.go:358
ObjectLocking: outputArtifact.S3.CreateBucketIfNotPresent.ObjectLocking,
})
alreadyExists := bucketAlreadyExistsErr(makeBucketErr)
log.WithField("bucket", outputArtifact.S3.Bucket).
WithField("alreadyExists", alreadyExists).
WithError(makeBucketErr).
Info(ctx, "create bucket failed")
if makeBucketErr != nil && !alreadyExists {
return !isTransientS3Err(ctx, makeBucketErr), fmt.Errorf("failed to create bucket %s: %w", outputArtifact.S3.Bucket, makeBucketErr)
}
}
if isDir {
if err = s3cli.PutDirectory(outputArtifact.S3.Bucket, outputArtifact.S3.Key, path); err != nil {
return !isTransientS3Err(ctx, err), fmt.Errorf("failed to put directory: %w", err)
}
} else {
if err = s3cli.PutFile(outputArtifact.S3.Bucket, outputArtifact.S3.Key, path); err != nil {
return !isTransientS3Err(ctx, err), fmt.Errorf("failed to put file: %w", err)
}
}
return true, nil
}
func bucketAlreadyExistsErr(err error) bool {
resp := &minio.ErrorResponse{}
// https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
alreadyExistsCodes := map[string]bool{"BucketAlreadyExists": true, "BucketAlreadyOwnedByYou": true}
return errors.As(err, resp) && alreadyExistsCodes[resp.Code]
}
// ListObjects returns the files inside the directory represented by the Artifact
func (s3Driver *ArtifactDriver) ListObjects(ctx context.Context, artifact *wfv1.Artifact) ([]string, error) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
var files []stringView on GitHub (pinned to 35bff19146)
Solutions
- Check the wrapped underlying error cause for the real S3 failure (permissions, missing bucket, credentials)
- Verify s3 bucket/endpoint/keyFormat in the artifact repository config and the artifact's S3 key
- Confirm the artifact source path exists in the container and the step actually produced the file
- Test credentials with aws s3 cp or mc cp against the same endpoint/bucket
Example fix
// before s3cli.PutFile(bucket, key, path) // fails: bucket missing // after # create/verify bucket first aws --endpoint-url $ENDPOINT s3 mb s3://my-bucket
Defensive patterns
Strategy: retry
Validate before calling
// pre-flight: ensure artifact source exists and bucket is writable
if _, err := os.Stat(path); err != nil { return fmt.Errorf("artifact path missing: %w", err) }
_, err := mc.StatObject(ctx, bucket, keyPrefix, minio.StatObjectOptions{}) Try / catch
// executor already retries transient errors; on workflow failure
if strings.Contains(err.Error(), "failed to put file") {
log.Printf("S3 put failed, check bucket/creds: %v", errors.Unwrap(err))
} Prevention
- Verify bucket exists and IAM allows s3:PutObject before submitting workflows
- Test artifact credentials with aws s3 cp / mc cp from a pod in the same namespace
- Keep output artifacts written before step exit so the path exists at save time
- Monitor for Throttling/SlowDown and increase retry backoff
When it happens
Trigger: saveS3Artifact calls s3cli.PutFile and Minio returns an error: wrong bucket/key permissions, missing bucket, nonexistent local path, invalid credentials, or S3 outage beyond the retry backoff.
Common situations: IAM/Minio policy denies s3:PutObject; artifact repository bucket misconfigured in workflow-controller-configmap; accessKey/secretKey wrong or rotated; local file deleted before save; endpoint TLS misconfiguration.
Related errors
- Failed to save artifact: %v
- error appending filename %s to key of artifact %+v: err: %w
- failed to get directory: %w
- failed to put directory: %w
- failed to check if key %s exists from bucket %s: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/273ba561726e8eaa.
Report an issue: GitHub.