microsoft/aspire · error · InvalidOperationException

The Aspire skills bundle staging directory must have a…

Error message

The Aspire skills bundle staging directory must have a parent directory.

What it means

EmbeddedAspireSkillsBundleProvider.CreateBundleAsync creates a staging directory for the embedded skills bundle and needs its parent to host temporary files. This guard throws when bundleDirectory.Parent is null, i.e. the staging path is a filesystem root (or otherwise has no parent). It is an internal invariant check — normal CLI usage never passes a root path here.

Solutions

  1. Check and fix the TMP/TEMP environment variables (or the Aspire cache-path override) so they point to a real subdirectory, not a drive/filesystem root.
  2. Point the override at e.g. %TEMP%\aspire or /tmp/aspire and re-run the command.
  3. If running in a container/sandbox, ensure a writable non-root temp directory is mounted and referenced.

Example fix

// before
set TEMP=C:\
// after
set TEMP=C:\Users\me\AppData\Local\Temp
Defensive patterns

Strategy: validation

Validate before calling

if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TMP")) ||
    Path.GetPathRoot(Path.GetFullPath(Environment.GetEnvironmentVariable("TMP")!)) == Path.GetFullPath(Environment.GetEnvironmentVariable("TMP")!))
{
    // fix TEMP/TMP to a non-root directory before running the CLI
}

Prevention

When it happens

Trigger: Thrown in CreateBundleAsync when the resolved bundle staging directory (bundleDirectory) has no Parent — e.g. the temp/cache root resolved to a drive root like C:\ or /, typically because an environment override (TMP/TEMP or a cache-path setting) points at a root directory.

Common situations: TMP or TEMP environment variable set to a drive root on Windows; a custom ASPIRE cache/home override pointing at "/"; exotic sandbox/container setups with unusual temp paths.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/76d5d6b4f18f5888. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Cli/Agents/AspireSkills/EmbeddedAspireSkillsBundleProvider.cs:71

        CancellationToken cancellationToken)
    {
        ArgumentNullException.ThrowIfNull(bundleDirectory);

        var metadata = Metadata;
        if (metadata is null || string.IsNullOrWhiteSpace(metadata.Sha512))
        {
            return null;
        }

        await using var archiveStream = OpenArchive();
        if (archiveStream is null)
        {
            return null;
        }

        Directory.CreateDirectory(bundleDirectory.FullName);
        var temporaryDirectoryRoot = bundleDirectory.Parent
            ?? throw new InvalidOperationException("The Aspire skills bundle staging directory must have a parent directory.");
        // Keep the archive beside the staging directory so a transient Windows file lock during
        // best-effort cleanup cannot prevent the validated staging directory from being published.
        using var temporaryDirectory = TemporaryCacheDirectory.Create(
            temporaryDirectoryRoot.FullName,
            "embedded",
            path => FileDeleteHelper.TryDeleteDirectory(path),
            path => FileDeleteHelper.TryDeleteFile(path));
        var archivePath = Path.Combine(temporaryDirectory.FullName, "bundle.tgz");

        await using (var fileStream = File.Create(archivePath))
        {
            await archiveStream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false);
        }

        return await _bundleProvider.CreateAsync(
            new FileInfo(archivePath),
            bundleDirectory,
            metadata.Sha512,

View on GitHub (pinned to 25830f84bd)