{"record":{"id":"46bea6996fe634af","repo":"microsoft/aspire","slug":"could-not-replace-aspire-skills-cache-directory-0","errorCode":null,"errorMessage":"Could not replace Aspire skills cache directory '{0}'.","messagePattern":"Could not replace Aspire skills cache directory '(.+?)'\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Cli/Agents/AspireSkills/AspireSkillsInstaller.cs","lineNumber":811,"sourceCode":"            version,\n            archiveSha512,\n            githubArchiveSha256,\n            requireVerifiedGitHubSource: source == BundleArchiveSource.VerifiedGitHub,\n            skipCompatibilityCheck: source == BundleArchiveSource.Embedded,\n            activity: null,\n            cancellationToken).ConfigureAwait(false);\n        if (cachedResult is not null)\n        {\n            return cachedResult.Bundle!;\n        }\n\n        if (Directory.Exists(targetDir))\n        {\n            logger.LogDebug(\"Replacing Aspire skills cache directory {CacheDirectory}.\", targetDir);\n            TryDeleteDirectory(targetDir);\n            if (Directory.Exists(targetDir))\n            {\n                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, \"Could not replace Aspire skills cache directory '{0}'.\", targetDir));\n            }\n        }\n\n        Directory.CreateDirectory(versionCacheDirectory);\n        RemoveLegacyCacheLayout(versionCacheDirectory);\n        stageDirectory.MoveTo(targetDir);\n        TouchLastUsed(targetDir);\n\n        return stagedBundle;\n    }\n\n    private static void RemoveInstallerMetadata(string bundleDirectory)\n    {\n        // These files describe local installer state, not bundle content. Always recreate them\n        // from the acquisition path so an archive cannot claim freshness or GitHub provenance.\n        File.Delete(Path.Combine(bundleDirectory, ArchiveSha512FileName));\n        File.Delete(Path.Combine(bundleDirectory, GitHubArchiveSha256FileName));\n        File.Delete(Path.Combine(bundleDirectory, GitHubAttestationVerifiedFileName));","sourceCodeStart":793,"sourceCodeEnd":829,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Cli/Agents/AspireSkills/AspireSkillsInstaller.cs#L793-L829","documentation":"AspireSkillsInstaller attempts an atomic replacement of the Aspire skills cache directory by deleting the existing target and moving a staged directory into place. This error is thrown when the old target directory still exists after a delete was attempted, because the MoveTo would otherwise fail or merge incorrectly. It almost always indicates an external process (or antivirus/indexer) is holding a lock on files inside the directory, or the user lacks delete permission.","triggerScenarios":"Occurs during skill cache install/refresh when Directory.Exists(targetDir) is still true after TryDeleteDirectory(targetDir). Caused by open file handles in the cache dir, read-only attributes, antivirus scans, or insufficient ACLs on the cache path.","commonSituations":"Another aspire CLI process or editor is concurrently reading the skills cache; Windows Defender or a search indexer temporarily locks files; the cache lives on a network share or synced folder (OneDrive/Dropbox) with lock/pin semantics; running under a restricted service account.","solutions":["Close other aspire/CLI processes and editors that may hold handles under the skills cache directory, then retry the command.","Manually delete the cache directory reported in the message (checking for read-only files) and re-run the install.","Temporarily exclude the cache directory from antivirus/indexing if locks recur.","Re-run the command in an elevated shell if the cache is under a protected path (e.g. Program Files).","Retry after a short delay — transient Windows locks (e.g. from AV scans) often clear on their own."],"exampleFix":"// before\nshell: rm -rf partially-locked-cache && aspire skills install\n// after\n# close other CLI sessions first, then\nrm -rf ~/.aspire/skills/cache/<version>\naspire skills install","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try\n{\n    await installer.InstallAsync(...);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Could not replace Aspire skills cache directory\"))\n{\n    // wait for locks to clear, close other processes, then retry once\n}","preventionTips":["Avoid running multiple aspire CLI commands that touch the skills cache concurrently.","Keep the skills cache outside antivirus/indexer-heavy and file-sync (OneDrive/Dropbox) directories.","Ensure the cache path is user-writable and not under a protected system directory."],"tags":["filesystem","file-lock","cache","cli"],"backgroundTag":"file-write-failed","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}