quarkusio/quarkus · error · IOException

Failed to create JBang download directory: ${dir}

Error message

Failed to create JBang download directory: ${dir}

What it means

JBangSupport.installJBang throws IOException 'Failed to create JBang download directory: <absolute path>' when the temporary download directory used to unzip JBang cannot be created. Normally Files.createTempDirectory succeeds, so this fires only in a race or hostile environment where the dir disappears or cannot be materialized. It propagates wrapped as a runtime exception from doEnsureJBangIsInstalledInternal.

Source

Thrown at independent-projects/tools/devtools-common/src/main/java/io/quarkus/cli/plugin/JBangSupport.java:188

    }

    private Path getInstallationDir() {
        Path currentDir = workingDirectory;
        Optional<Path> dir = Optional.ofNullable(currentDir).filter(EXISTS_AND_WRITABLE);
        while (dir.map(Path::getParent).filter(EXISTS_AND_WRITABLE).isPresent()) {
            dir = dir.map(Path::getParent);
        }
        return dir.map(d -> d.resolve(".jbang"))
                .orElseThrow(() -> new IllegalStateException("Failed to determine .jbang directory"));
    }

    private void installJBang() {
        try {
            String uri = "https://www.jbang.dev/releases/latest/download/jbang.zip";
            Path downloadDir = Files.createTempDirectory("jbang-download-");

            if (!downloadDir.toFile().exists() && !downloadDir.toFile().mkdirs()) {
                throw new IOException("Failed to create JBang download directory: " + downloadDir.toAbsolutePath().toString());
            }

            Path downloadFile = downloadDir.resolve("jbang.zip");
            Path installDir = getInstallationDir();
            if (!installDir.toFile().exists() && !installDir.toFile().mkdirs()) {
                throw new IOException("Failed to create JBang install directory: " + installDir.toAbsolutePath().toString());
            }
            HttpClient client = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.ALWAYS).build();
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(new URI(uri))
                    .GET()
                    .build();
            HttpResponse<Path> response = client.send(request, BodyHandlers.ofFile(downloadFile));
            ZipUtils.unzip(downloadFile, downloadDir);
            ZipUtils.copyFromZip(downloadDir.resolve("jbang"), installDir);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Verify java.io.tmpdir/TMPDIR is writable (touch a file there) and has free space
  2. Set -Djava.io.tmpdir to a writable directory and retry the command
  3. Re-run the installation — temp directory races are often transient

Example fix

// before
export TMPDIR=/nonexistent-quarkus-tmp

// after
export TMPDIR=$HOME/.tmp && mkdir -p $TMPDIR
Defensive patterns

Strategy: try-catch

Validate before calling

Path tmp = Paths.get(System.getProperty("java.io.tmpdir"));
if (!Files.isDirectory(tmp) || !Files.isWritable(tmp))
    throw new IllegalStateException("Temp dir not writable: " + tmp);

Try / catch

try {
    jbangSupport.ensureJBangIsInstalled();
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().contains("Failed to create JBang download directory")) {
        // point TMPDIR/-Djava.io.tmpdir at a writable dir and retry
    } else throw e;
}

Prevention

When it happens

Trigger: Calling ensureJBangIsInstalled (leading to installJBang) when downloadDir.toFile() does not exist and File.mkdirs() fails — e.g. temp dir deleted concurrently or permissions on java.io.tmpdir.

Common situations: Read-only or full /tmp; TMPDIR pointing to an unwritable location; security policies (sandboxed CI) blocking temp directory creation; cleanup daemon deleting temp dirs mid-run.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/92ae05e1307cf27b. Report an issue: GitHub.