arduino/Arduino · error · IOException

Invalid archive: it must contain a single root folder

Error message

Invalid archive: it must contain a single root folder

What it means

When extract() is asked to strip a root folder (stripPath > 0), it computes the common path prefix from the first entry's name by skipping stripPath '/' characters. If the entry name contains fewer slashes than requested, it throws this IOException, because the archive does not have the single root folder the caller expects to strip.

Source

Thrown at arduino-core/src/cc/arduino/utils/ArchiveExtractor.java:170

          continue;
        }

        if (entry instanceof TarArchiveEntry) {
          TarArchiveEntry tarEntry = (TarArchiveEntry) entry;
          mode = tarEntry.getMode();
          isLink = tarEntry.isLink();
          isSymLink = tarEntry.isSymbolicLink();
          linkName = tarEntry.getLinkName();
        }

        // On the first archive entry, if requested, detect the common path
        // prefix to be stripped from filenames
        if (stripPath > 0 && pathPrefix.isEmpty()) {
          int slash = 0;
          while (stripPath > 0) {
            slash = name.indexOf("/", slash);
            if (slash == -1) {
              throw new IOException("Invalid archive: it must contain a single root folder");
            }
            slash++;
            stripPath--;
          }
          pathPrefix = name.substring(0, slash);
        }

        // Strip the common path prefix when requested
        if (!name.startsWith(pathPrefix)) {
          throw new IOException("Invalid archive: it must contain a single root folder while file " + name + " is outside " + pathPrefix);
        }
        name = name.substring(pathPrefix.length());
        if (name.isEmpty()) {
          continue;
        }
        File outputFile = new File(destFolder, name);

        File outputLinkedFile = null;

View on GitHub (pinned to a0df6e0e83)

Solutions

  1. Repackage the archive so all files sit under a single top-level folder named after the library (e.g. MyLibrary/src/...)
  2. Call extract with stripPath=0 if the archive legitimately has no root folder and you want files extracted as-is
  3. Inspect the archive (tar -tf) to confirm the directory layout before extracting

Example fix

// before
archiveExtractor.extract(archiveFile, destFolder, 1); // archive is flat
// after (repack with root folder) OR:
archiveExtractor.extract(archiveFile, destFolder, 0); // no strip requested
Defensive patterns

Strategy: validation

Validate before calling

// inspect first entry layout before choosing stripPath
try (TarArchiveInputStream in = new TarArchiveInputStream(new FileInputStream(archiveFile))) {
  TarArchiveEntry e = in.getNextTarEntry();
  if (e != null && e.getName().indexOf('/') == -1) throw new IllegalArgumentException("Archive has no root folder; use stripPath=0 or repackage");
}

Try / catch

try { extractor.extract(archive, dest, 1); } catch (IOException e) { if (e.getMessage().contains("single root folder")) { extractor.extract(archive, dest, 0); } else { throw e; } }

Prevention

When it happens

Trigger: extract(file, dest, stripPath=N) with N=1 (typical) but the first archive entry's path has no '/' — e.g. the archive contains files at its root or a single file instead of a top-level directory.

Common situations: Library released as a flat archive (files at archive root, no wrapping folder); archive whose first entry is './name' or a bare filename; someone re-zips library contents without the standard 'LibraryName/' root directory.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of arduino/Arduino@a0df6e0e83 (2026-09-06). Data as JSON: /api/errors/c14fe6c936ef20e0. Report an issue: GitHub.