{"record":{"id":"e812feb4e897cb0a","repo":"argoproj/argo-workflows","slug":"failed-to-test-if-s-s-is-a-directory-w","errorCode":null,"errorMessage":"failed to test if %s/%s is a directory: %w","messagePattern":"failed to test if (.+?)/(.+?) is a directory: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"workflow/artifacts/oss/oss.go","lineNumber":161,"sourceCode":"\t\t\t\treturn !isTransientOSSErr(ctx, err), err\n\t\t\t}\n\t\t\tobjectName := inputArtifact.OSS.Key\n\t\t\tdirPath := filepath.Dir(path)\n\t\t\terr = os.MkdirAll(dirPath, 0o700)\n\t\t\tif err != nil {\n\t\t\t\treturn false, fmt.Errorf(\"mkdir %s error: %w\", dirPath, err)\n\t\t\t}\n\t\t\torigErr := bucket.GetObjectToFile(objectName, path)\n\t\t\tif origErr == nil {\n\t\t\t\treturn true, nil\n\t\t\t}\n\t\t\tif !IsOssErrCode(origErr, \"NoSuchKey\") {\n\t\t\t\treturn !isTransientOSSErr(ctx, origErr), fmt.Errorf(\"failed to get file: %w\", origErr)\n\t\t\t}\n\t\t\t// If we get here, the error was a NoSuchKey. The key might be a oss \"directory\"\n\t\t\tisDir, err := IsOssDirectory(bucket, objectName)\n\t\t\tif err != nil {\n\t\t\t\treturn !isTransientOSSErr(ctx, err), fmt.Errorf(\"failed to test if %s/%s is a directory: %w\", bucketName, objectName, err)\n\t\t\t}\n\t\t\tif !isDir {\n\t\t\t\t// It's neither a file, nor a directory. Return the original NoSuchKey error\n\t\t\t\treturn false, origErr\n\t\t\t}\n\n\t\t\tif err = GetOssDirectory(ctx, bucket, objectName, path); err != nil {\n\t\t\t\treturn !isTransientOSSErr(ctx, err), fmt.Errorf(\"failed get directory: %w\", err)\n\t\t\t}\n\t\t\treturn true, nil\n\t\t})\n\treturn err\n}\n\n// OpenStream opens a stream reader for an artifact from OSS compliant storage\nfunc (ossDriver *ArtifactDriver) OpenStream(ctx context.Context, inputArtifact *wfv1.Artifact) (io.ReadCloser, error) {\n\tvar stream io.ReadCloser\n\terr := waitutil.Backoff(defaultRetry,","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/workflow/artifacts/oss/oss.go#L143-L179","documentation":"After OSS returns NoSuchKey, Load checks whether the key is actually an OSS 'directory' via IsOssDirectory (a list-objects call under the prefix). If that directory probe itself errors (permissions on ListObjects, network failure), Load fails with 'failed to test if <bucket>/<key> is a directory'.","triggerScenarios":"GetObjectToFile returns NoSuchKey and the follow-up IsOssDirectory(bucket, objectName) errors — most often the credentials lack oss:ListObjects permission on the bucket, or a transient network failure during the list call after retries.","commonSituations":"RAM policies that grant GetObject but not ListObjects (common with least-privilege setups); keys pointing to folder-style prefixes while the policy only allows reading specific objects; intermittent OSS connectivity with retry budget exhausted.","solutions":["Grant the OSS credentials oss:ListObjects (ListBucket) permission on the bucket.","If the artifact should be a file, check the exact key spelling — a wrong key triggers the NoSuchKey+probe path; fix the key to avoid the probe entirely.","For intermittent causes, retry the workflow; isTransientOSSErr already filters retryable codes.","Ensure the STS role policy includes both GetObject and ListBucket actions."],"exampleFix":"// before (RAM policy)\n{ \"Statement\": [{ \"Action\": [\"oss:GetObject\"], \"Effect\": \"Allow\" }] }\n// after\n{ \"Statement\": [{ \"Action\": [\"oss:GetObject\", \"oss:ListObjects\"], \"Effect\": \"Allow\" }] }","handlingStrategy":"validation","validationCode":"// ensure creds can list before workflows that may hit directory keys\ncli, _ := oss.New(endpoint, ak, sk)\nb, _ := cli.Bucket(bucket)\n_, err := b.ListObjects(oss.Prefix(key), oss.MaxKeys(1))\nif err != nil {\n\treturn fmt.Errorf(\"credentials lack ListObjects on %s: %w\", bucket, err)\n}","typeGuard":null,"tryCatchPattern":"err := driver.Load(ctx, art, path)\nif err != nil && strings.Contains(err.Error(), \"is a directory\") {\n\t// list-permission or transient failure during NoSuchKey probe; check RAM policy\n}","preventionTips":["Include oss:ListObjects/ListBucket in RAM policies whenever directory-style keys are possible","Use exact object keys instead of folder prefixes to skip the probe path entirely","Retry transient failures — isTransientOSSErr already marks retryable codes"],"tags":["oss","artifact","permissions","listobjects","nosuchkey"],"backgroundTag":"oss-directory-probe-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"}