{"record":{"id":"613adda6c9f0eb2a","repo":"alibaba/ARouter","slug":"cannot-create-arouter-transform-output-directory","errorCode":null,"errorMessage":"Cannot create ARouter transform output directory: <parent>","messagePattern":"Cannot create ARouter transform output directory: <parent>","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"arouter-gradle-plugin/src/main/groovy/com/alibaba/android/arouter/register/core/ScopedClassTransformer.groovy","lineNumber":40,"sourceCode":"    private static final List<String> REGISTER_INTERFACES = [\n            'com/alibaba/android/arouter/facade/template/IRouteRoot',\n            'com/alibaba/android/arouter/facade/template/IInterceptorGroup',\n            'com/alibaba/android/arouter/facade/template/IProviderGroup'\n    ].asImmutable()\n\n    static Result transform(Collection<File> jars, Collection<File> directories, File output) {\n        Map<String, Set<String>> implementations = new LinkedHashMap<>()\n        REGISTER_INTERFACES.each { implementations.put(it, new TreeSet<String>()) }\n\n        jars.each { scanJar(it, implementations) }\n        directories.each { scanDirectory(it, implementations) }\n\n        Set<String> registrations = new TreeSet<>()\n        implementations.values().each { registrations.addAll(it) }\n\n        File parent = output.parentFile\n        if (!parent.isDirectory() && !parent.mkdirs()) {\n            throw new IOException('Cannot create ARouter transform output directory: ' + parent)\n        }\n\n        File temporary = new File(parent, output.name + '.tmp')\n        if (temporary.exists() && !temporary.delete()) {\n            throw new IOException('Cannot replace temporary ARouter transform output: ' + temporary)\n        }\n\n        boolean logisticsCenterFound = false\n        Set<String> writtenEntries = new HashSet<>()\n\n        try {\n            JarOutputStream jarOutput = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(temporary)))\n            try {\n                jars.each { File jar ->\n                    logisticsCenterFound |= copyJar(jar, jarOutput, writtenEntries, registrations)\n                }\n                directories.each { File directory ->\n                    logisticsCenterFound |= copyDirectory(directory, jarOutput, writtenEntries, registrations)","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/alibaba/ARouter/blob/84f451d244e3fb1d0e37801de1b9ee2af2f81d68/arouter-gradle-plugin/src/main/groovy/com/alibaba/android/arouter/register/core/ScopedClassTransformer.groovy#L22-L58","documentation":"Thrown by ScopedClassTransformer when writing the transform output: it tries mkdirs() on the output's parent directory and, if that fails (parent still not a directory), throws an IOException naming the directory path. This guarantees ARouter's class-registration transform has a valid destination before writing files.","triggerScenarios":"The parent directory of the transform output does not exist and File.mkdirs() returns false — e.g. a path segment is an existing file, the path is read-only, disk is full, or a race removed the directory.","commonSituations":"Build output directories cleaned by another process mid-build; running Gradle with unusual buildDir pointing at a read-only location (CI cache, docker volume); antivirus locking the directory on Windows.","solutions":["Run `./gradlew clean` and rebuild so the output directory tree is recreated fresh.","Check that no file exists at the reported parent path and remove/rename it.","Verify the build directory and its parents are writable by the build user (CI permissions, docker user, antivirus)."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"File parent = output.parentFile\nif (!parent.isDirectory() && new File(parent.path).isFile()) {\n    throw new IllegalStateException(\"Path exists as a file, blocking mkdir: \" + parent)\n}","typeGuard":null,"tryCatchPattern":"try {\n    transform(...)\n} catch (IOException e) {\n    if (e.message?.contains('Cannot create ARouter transform output directory')) {\n        new File(e.message.split(': ').last()).let { it.delete(); it.mkdirs() }\n        // then retry once\n    } else throw e\n}","preventionTips":["Run clean builds after unusual failures to rebuild directory trees.","Verify buildDir is on a writable volume (not a read-only CI cache).","Exclude build dirs from antivirus real-time scanning.","Avoid custom buildDir pointing inside existing files."],"tags":["gradle-plugin","filesystem","io"],"backgroundTag":"mkdir-permission-denied","analyzedSha":"84f451d244e3fb1d0e37801de1b9ee2af2f81d68","analyzedAt":"2026-09-06T13:30:41.084Z","contentChangedAt":"2026-09-06T13:30:41.084Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}