{"record":{"id":"f636eb03ce7d8302","repo":"argoproj/argo-workflows","slug":"failed-to-put-directory-w","errorCode":null,"errorMessage":"failed to put directory: %w","messagePattern":"failed to put directory: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"workflow/artifacts/s3/s3.go","lineNumber":354,"sourceCode":"\tif createBucketIfNotPresent != nil {\n\t\tlog.WithField(\"bucket\", outputArtifact.S3.Bucket).Info(ctx, \"creating bucket\")\n\t\tmakeBucketErr := s3cli.MakeBucket(outputArtifact.S3.Bucket, minio.MakeBucketOptions{\n\t\t\tRegion:        outputArtifact.S3.Region,\n\t\t\tObjectLocking: outputArtifact.S3.CreateBucketIfNotPresent.ObjectLocking,\n\t\t})\n\t\talreadyExists := bucketAlreadyExistsErr(makeBucketErr)\n\t\tlog.WithField(\"bucket\", outputArtifact.S3.Bucket).\n\t\t\tWithField(\"alreadyExists\", alreadyExists).\n\t\t\tWithError(makeBucketErr).\n\t\t\tInfo(ctx, \"create bucket failed\")\n\t\tif makeBucketErr != nil && !alreadyExists {\n\t\t\treturn !isTransientS3Err(ctx, makeBucketErr), fmt.Errorf(\"failed to create bucket %s: %w\", outputArtifact.S3.Bucket, makeBucketErr)\n\t\t}\n\t}\n\n\tif isDir {\n\t\tif err = s3cli.PutDirectory(outputArtifact.S3.Bucket, outputArtifact.S3.Key, path); err != nil {\n\t\t\treturn !isTransientS3Err(ctx, err), fmt.Errorf(\"failed to put directory: %w\", err)\n\t\t}\n\t} else {\n\t\tif err = s3cli.PutFile(outputArtifact.S3.Bucket, outputArtifact.S3.Key, path); err != nil {\n\t\t\treturn !isTransientS3Err(ctx, err), fmt.Errorf(\"failed to put file: %w\", err)\n\t\t}\n\t}\n\treturn true, nil\n}\n\nfunc bucketAlreadyExistsErr(err error) bool {\n\tresp := &minio.ErrorResponse{}\n\t// https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html\n\talreadyExistsCodes := map[string]bool{\"BucketAlreadyExists\": true, \"BucketAlreadyOwnedByYou\": true}\n\treturn errors.As(err, resp) && alreadyExistsCodes[resp.Code]\n}\n\n// ListObjects returns the files inside the directory represented by the Artifact\nfunc (s3Driver *ArtifactDriver) ListObjects(ctx context.Context, artifact *wfv1.Artifact) ([]string, error) {","sourceCodeStart":336,"sourceCodeEnd":372,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/workflow/artifacts/s3/s3.go#L336-L372","documentation":"The upload itself failed: after bucket handling, PutDirectory (if the local path is a directory) could not upload the directory contents to the S3 key prefix. The whole artifact save fails and the retry wrapper decides whether to retry.","triggerScenarios":"saveS3Artifact with isDir=true: s3cli.PutDirectory(bucket, key, path) failed — transient S3 error (throttle/network), access denied on PutObject, multipart upload failure on large trees, or prefix name conflicts.","commonSituations":"Uploading large artifact directories that hit timeouts/rate limits; IAM lacking s3:PutObject; MinIO disk full server-side; flaky network between executor and endpoint causing repeated retries that eventually give up.","solutions":["Retry the workflow step — transient errors are retried by the executor backoff","Verify s3:PutObject (and s3:ListBucket) on the target bucket/prefix","Check MinIO server disk/capacity if using MinIO","Increase artifact bandwidth/reduce artifact size or split the directory","Check the endpoint network path (DNS, TLS, proxies) from the workflow pod"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"aws s3api head-bucket --bucket my-bucket && aws s3api put-object --bucket my-bucket --key .probe --body /dev/null","typeGuard":null,"tryCatchPattern":"err := s3Driver.Save(ctx, path, art)\nif err != nil {\n    if isTransientS3Err(ctx, err) {\n        // executor already retried; surface or re-run the node\n    }\n    return fmt.Errorf(\"artifact upload failed: %w\", err)\n}","preventionTips":["Grant s3:PutObject on the artifact prefix","Keep artifacts modest in size; tar/compress large directories","Monitor MinIO capacity and S3 5xx/throttle metrics","Ensure stable network path from pods to the endpoint (no flaky DNS/proxy)"],"tags":["s3","artifacts","upload","network"],"backgroundTag":"s3-upload-failed","analyzedSha":"35bff19146f5a6ada77468c431f2624bd577e373","analyzedAt":"2026-09-03T19:34:35.908Z","contentChangedAt":"2026-09-03T19:34:35.908Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}