{"record":{"id":"69af945d87535a35","repo":"apache/dolphinscheduler","slug":"directory-coskey-already-exists","errorCode":null,"errorMessage":"directory: ${cosKey} already exists","messagePattern":"directory: (.+?) already exists","errorType":"exception","errorClass":"FileAlreadyExistsException","httpStatus":null,"severity":"error","filePath":"dolphinscheduler-storage-plugin/dolphinscheduler-storage-cos/src/main/java/org/apache/dolphinscheduler/plugin/storage/cos/CosStorageOperator.java","lineNumber":127,"sourceCode":"    public String getStorageBaseDirectory() {\n        // All directory should end with File.separator\n        if (resourceBaseAbsolutePath.startsWith(File.separator)) {\n            String warnMessage =\n                    String.format(\"%s -> %s should not start with %s in tencent cos\",\n                            StorageConstants.RESOURCE_UPLOAD_PATH,\n                            resourceBaseAbsolutePath, File.separator);\n            log.warn(warnMessage);\n            return resourceBaseAbsolutePath.substring(1);\n        }\n        return resourceBaseAbsolutePath;\n    }\n\n    @SneakyThrows\n    @Override\n    public void createStorageDir(String directoryAbsolutePath) {\n        String cosKey = transformAbsolutePathToCOSKey(directoryAbsolutePath);\n        if (cosClient.doesObjectExist(bucketName, cosKey)) {\n            throw new FileAlreadyExistsException(\"directory: \" + cosKey + \" already exists\");\n        }\n        ObjectMetadata metadata = new ObjectMetadata();\n        metadata.setContentLength(0L);\n        InputStream emptyContent = new ByteArrayInputStream(new byte[0]);\n        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, cosKey, emptyContent, metadata);\n        cosClient.putObject(putObjectRequest);\n    }\n\n    @SneakyThrows\n    @Override\n    public void download(String srcFilePath, String dstFilePath, boolean overwrite) {\n        String cosKey = transformAbsolutePathToCOSKey(srcFilePath);\n        Path dsTempFolder = Paths.get(FileUtils.DATA_BASEDIR).normalize().toAbsolutePath();\n        Path fileDownloadPathNormalized = dsTempFolder.resolve(dstFilePath).normalize().toAbsolutePath();\n        if (!fileDownloadPathNormalized.startsWith(dsTempFolder)) {\n            // if the destination file path is NOT in DS temp folder (e.g., '/tmp/dolphinscheduler'),\n            // an IllegalArgumentException should be thrown.\n            throw new IllegalArgumentException(\"failed to download to \" + fileDownloadPathNormalized);","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/apache/dolphinscheduler/blob/02eac45a1b6676e639fcbfb4be2243de5771b05d/dolphinscheduler-storage-plugin/dolphinscheduler-storage-cos/src/main/java/org/apache/dolphinscheduler/plugin/storage/cos/CosStorageOperator.java#L109-L145","documentation":"CosStorageOperator.createStorageDir creates a directory in Tencent COS by writing a zero-length object at the transformed key. If an object already exists at that key, it throws FileAlreadyExistsException instead of overwriting. COS directories are only emulated via key prefixes, so any pre-existing object at the key collides.","triggerScenarios":"Calling createStorageDir(directoryAbsolutePath) when cosClient.doesObjectExist(bucketName, cosKey) returns true — i.e., a prior mkdir, a file uploaded under the same path, or a leftover marker object.","commonSituations":"Re-running a workflow that previously created the same resource directory; uploading a resource file that occupies the key the directory wants; stale COS objects after tenant/resource renames.","solutions":["Check existence first with exists()/fetchFileList and skip or use a unique directory name","Delete the existing object (cosClient.deleteObject) if it is safe to overwrite, then retry createStorageDir","Use a timestamped or tenant-scoped directory path to avoid collisions"],"exampleFix":"// before\nstorageOperator.createStorageDir(resourcePath);\n// after\nif (!storageOperator.exists(resourcePath)) {\n    storageOperator.createStorageDir(resourcePath);\n}","handlingStrategy":"validation","validationCode":"if (cosStorageOperator.exists(cosKey)) { throw new IllegalStateException(cosKey + \" exists; choose another directory\"); }","typeGuard":null,"tryCatchPattern":"try {\n    operator.createStorageDir(dir);\n} catch (FileAlreadyExistsException e) {\n    log.info(\"Directory already present, reusing: {}\", dir);\n}","preventionTips":["Always guard createStorageDir with an exists() check","Scope directory names per workflow execution to avoid collisions","Remember COS directories are zero-byte marker objects; file uploads to the same key collide"],"tags":["storage","cos","duplicate-resource"],"backgroundTag":"file-already-exists","analyzedSha":"02eac45a1b6676e639fcbfb4be2243de5771b05d","analyzedAt":"2026-09-06T17:43:00.555Z","contentChangedAt":"2026-09-06T17:43:00.555Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}