ppy/osu · error · InvalidFormatException

{Path} is not a valid archive

Error message

{Path} is not a valid archive

What it means

Thrown by ImportTask.GetReader when the path is not recognized as any supported archive type: it's not a zip file (ZipUtils.IsZipArchive returns false), not a directory (Directory.Exists returns false), and not a file (File.Exists returns false). This is the path-based branch where no Stream was provided to the ImportTask.

Source

Thrown at osu.Game/Database/ImportTask.cs:58

            Path = filename;
            Stream = stream;
        }

        /// <summary>
        /// Retrieve an archive reader from this task.
        /// </summary>
        public ArchiveReader GetReader()
        {
            if (Stream == null)
            {
                if (ZipUtils.IsZipArchive(Path))
                    return new ZipArchiveReader(File.Open(Path, FileMode.Open, FileAccess.Read, FileShare.Read), System.IO.Path.GetFileName(Path));
                if (Directory.Exists(Path))
                    return new DirectoryArchiveReader(Path);
                if (File.Exists(Path))
                    return new SingleFileArchiveReader(Path);

                throw new InvalidFormatException($"{Path} is not a valid archive");
            }

            if (Stream is not MemoryStream memoryStream)
            {
                // Path used primarily in tests (converting `ManifestResourceStream`s to `MemoryStream`s).
                memoryStream = new MemoryStream(Stream.ReadAllBytesToArray());
                Stream.Dispose();
            }

            if (ZipUtils.IsZipArchive(memoryStream))
                return new ZipArchiveReader(memoryStream, Path);

            return new MemoryStreamArchiveReader(memoryStream, Path);
        }

        /// <summary>
        /// Deletes the file that is encapsulated by this <see cref="ImportTask"/>.
        /// </summary>

View on GitHub (pinned to d9c73e12ad)

Solutions

  1. Verify the path exists before creating the ImportTask: check File.Exists(path) || Directory.Exists(path).
  2. Ensure the path is absolute and correctly formatted.
  3. If importing a zip, verify ZipUtils.IsZipArchive(path) returns true.
  4. If the file was moved or deleted, provide the correct current path or use the stream-based ImportTask constructor.

Example fix

// before
var task = new ImportTask(path);
var reader = task.GetReader(); // throws if path doesn't exist

// after
if (!File.Exists(path) && !Directory.Exists(path))
    throw new FileNotFoundException($"Archive not found: {path}", path);
var task = new ImportTask(path);
var reader = task.GetReader();
Defensive patterns

Strategy: validation

Validate before calling

// Validate path before creating ImportTask
if (!File.Exists(path) && !Directory.Exists(path))
    throw new FileNotFoundException($"Path is not a valid archive: {path}", path);
var task = new ImportTask(path);

Type guard

static bool IsValidArchivePath(string path)
    => File.Exists(path) || Directory.Exists(path);

Try / catch

try
{
    var reader = task.GetReader();
}
catch (InvalidFormatException ex) when (ex.Message.Contains("not a valid archive"))
{
    Logger.Log($"Invalid archive path: {task.Path}", LoggingTarget.Database);
}

Prevention

When it happens

Trigger: Constructing `new ImportTask(path)` (path-based, no stream) and calling GetReader() where: the file doesn't exist at all, the path is a broken symlink, the file exists but isn't a valid zip (and somehow passes the File.Exists check but not IsZipArchive — actually the File.Exists branch returns SingleFileArchiveReader, so this throw fires when the path simply doesn't exist as file or directory and isn't a zip).

Common situations: Passing a path to an ImportTask where the file was deleted between task creation and GetReader call; a typo in the path; a path that points to a special file or broken symlink; a network path that's inaccessible.

Related errors


AI-assisted analysis of ppy/osu@d9c73e12ad (2026-08-13). Data as JSON: /api/errors/13fe5c495f9a5048. Report an issue: GitHub.