{"record":{"id":"28847534daa5dcbc","repo":"argoproj/argo-workflows","slug":"unable-to-list-files-in-s-w","errorCode":null,"errorMessage":"unable to list files in %s: %w","messagePattern":"unable to list files in (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"workflow/artifacts/azure/azure.go","lineNumber":379,"sourceCode":"\t\tWithField(\"container\", artifact.Azure.Container).\n\t\tWithField(\"blob\", artifact.Azure.Blob).\n\t\tInfo(ctx, \"Deleting object from Azure Blob Storage\")\n\tcontainerClient, err := azblobDriver.newAzureContainerClient(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to create Azure Blob Container client: %w\", err)\n\t}\n\n\tisDir, err := azblobDriver.IsDirectory(ctx, artifact)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to test if %s is a directory: %w\", artifact.Azure.Blob, err)\n\t}\n\n\tif !isDir {\n\t\treturn DeleteBlob(ctx, containerClient, artifact.Azure.Blob, true)\n\t}\n\tfiles, err := azblobDriver.ListObjects(ctx, artifact)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to list files in %s: %w\", artifact.Azure.Blob, err)\n\t}\n\tdirectoryFile := \"\"\n\tfor _, file := range files {\n\t\tif file == artifact.Azure.Blob {\n\t\t\tdirectoryFile = file\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := DeleteBlob(ctx, containerClient, file, true); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif directoryFile != \"\" {\n\t\treturn DeleteBlob(ctx, containerClient, directoryFile, true)\n\t}\n\treturn nil\n}\n","sourceCodeStart":361,"sourceCodeEnd":397,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/workflow/artifacts/azure/azure.go#L361-L397","documentation":"When Delete determines the artifact is a directory prefix, it enumerates all blobs under the prefix with ListObjects before deleting them one by one. If that listing fails, Delete aborts with this error rather than partially deleting the directory.","triggerScenarios":"Delete on a directory-style artifact (prefix with blobs beneath it) where the ListBlobsFlat pager fails: auth rejection, network failure, container not found, or the client could not be created.","commonSituations":"Very large prefixes timing out through proxies; container deleted between IsDirectory and ListObjects; expired SAS token mid-operation; firewall rules blocking the data-plane listing.","solutions":["Check the wrapped error for auth (403) vs network causes.","Verify the container exists and credentials have 'Storage Blob Data Reader' role for listing.","Retry the delete; nothing has been deleted yet since listing precedes deletion.","If the prefix is huge and timing out, delete blobs in smaller prefix batches with az CLI or Azure Storage Explorer.","Ensure stable connectivity to the storage endpoint (no aggressive middlebox timeouts)."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// confirm the directory prefix is listable first\nfiles, err := driver.ListObjects(ctx, artifact)\nif err != nil {\n    return fmt.Errorf(\"cannot enumerate prefix %s before delete: %w\", artifact.Azure.Blob, err)\n}","typeGuard":null,"tryCatchPattern":"err := driver.Delete(ctx, artifact)\nif err != nil && strings.Contains(err.Error(), \"unable to list files\") {\n    // safe to retry: listing precedes deletion, nothing was deleted\n    err = retry.Do(ctx, func() error { return driver.Delete(ctx, artifact) })\n}","preventionTips":["Grant list permission (Storage Blob Data Reader / SAS 'l') on the container.","Keep directory prefixes modest in blob count to avoid long listings.","Handle transient 5xx with exponential backoff at the caller."],"tags":["azure","blob-storage","list-objects","network"],"backgroundTag":"azure-blob-list-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"}