arduino/Arduino · error · IOException

Invalid archive: it must contain a single root folder while

Error message

Invalid archive: it must contain a single root folder while file {name} is outside {pathPrefix}

What it means

After the expected root prefix is computed, every subsequent archive entry must start with that same prefix. If an entry's name lies outside the root folder (different top-level directory or a file at archive root), extract() throws this IOException naming the offending file and the expected prefix. This enforces the 'single root folder' convention used when installing libraries.

Source

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

        // 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;
        if (isLink) {
          if (!linkName.startsWith(pathPrefix)) {
            throw new IOException("Invalid archive: it must contain a single root folder while file " + linkName + " is outside " + pathPrefix);
          }
          linkName = linkName.substring(pathPrefix.length());
          outputLinkedFile = new File(destFolder, linkName);
        }
        if (isSymLink) {
          // Symbolic links are referenced with relative paths
          outputLinkedFile = new File(linkName);

View on GitHub (pinned to a0df6e0e83)

Solutions

  1. Repackage so every entry lives under the same single root folder
  2. Extract with a general-purpose tool (tar/7zip) and install the folder manually into libraries/
  3. Check entries for inconsistent prefixes (leading './', absolute paths) and normalize them before archiving

Example fix

// bad archive: README at root plus MyLib/ folder
// fix: move README inside the root folder
// tar contents before: README, MyLib/src/MyLib.cpp
// tar contents after: MyLib/README, MyLib/src/MyLib.cpp
Defensive patterns

Strategy: validation

Validate before calling

// ensure all entries share one root folder
try (TarArchiveInputStream in = new TarArchiveInputStream(new FileInputStream(archiveFile))) {
  TarArchiveEntry e;
  while ((e = in.getNextTarEntry()) != null) {
    if (e.getName().startsWith("../") || new File(e.getName()).isAbsolute()) throw new IllegalArgumentException("Unsafe entry: " + e.getName());
  }
}

Try / catch

try { extractor.extract(archive, dest, 1); } catch (IOException e) { if (e.getMessage().contains("is outside")) { repackArchiveWithSingleRoot(archive); } else { throw e; } }

Prevention

When it happens

Trigger: Archive contains entries from more than one top-level directory (e.g. both MyLib/ and Other/), or contains root-level files alongside the root folder, with stripPath=1 requested.

Common situations: Hand-assembled archives combining library files and extra files (README at root, license in another folder); archives built on different OSes with inconsistent leading './' entries; corrupted or maliciously crafted archives.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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