microsoft/aspire · error · InvalidOperationException

BrowserMessageStrings.BrowserLogsTrackedBrowserProfileConfli…

Error message

BrowserMessageStrings.BrowserLogsTrackedBrowserProfileConflict

What it means

ValidateProfileCompatibility (called from AcquireAsync) throws when a browser host for the same executable + user data root already exists under a tracked profile directory whose name differs from the requested one. One user data root maps to exactly one tracked profile; honoring a conflicting request would corrupt session isolation, so the registry refuses it.

Solutions

  1. Use one consistent profile configuration per (browser executable, user data root) pair.
  2. Request a different user data root if you need a different profile directory.
  3. Release all existing leases and let the tracked host shut down before re-acquiring with a different profile.

Example fix

// before
var first = await registry.AcquireAsync(new BrowserConfiguration { Browser = b, ProfileName = "default" }, ct);
var second = await registry.AcquireAsync(new BrowserConfiguration { Browser = b, ProfileName = "automation" }, ct); // same root, conflict

// after
var second = await registry.AcquireAsync(new BrowserConfiguration { Browser = b, ProfileName = "automation", UserDataRoot = alternateRoot }, ct);
Defensive patterns

Strategy: validation

Validate before calling

// Keep a single profile name per user data root across the application
private const string TrackedProfileName = "aspire-tracked"; // reuse everywhere instead of ad-hoc names

Try / catch

try { lease = await registry.AcquireAsync(config, ct); }
catch (InvalidOperationException ex) when (ex.Message.Contains("profile", StringComparison.OrdinalIgnoreCase)) { logger.LogError(ex, "Profile conflict on {Root}; use a distinct user data root or the existing profile.", config.UserDataRoot); }

Prevention

When it happens

Trigger: AcquireAsync with a configuration whose resolved user data root already hosts a tracked browser with a different profile directory name — e.g. the first lease used the default profile and a later lease requests a custom profile name for the same root.

Common situations: Mixing lease acquisitions with different profile settings for the same browser; two app hosts or two components sharing one user data directory but configured with different profile names; config drift between runs.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting.Browsers/BrowserHostRegistry.cs:365

        return profile;
    }

    private static void ValidateProfileCompatibility(BrowserHostIdentity identity, string? existingProfileDirectoryName, string? requestedProfileDirectoryName)
    {
        // A request without an explicit profile can attach to any tracked browser for the same user data root. Once a
        // caller asks for a named profile, however, reusing a host launched for a different profile would put the session
        // in the wrong browser context, so fail instead of silently attaching to the wrong profile.
        // Profile directory names are case-insensitive on Windows and macOS (default APFS) but case-sensitive on Linux.
        // We compare with OrdinalIgnoreCase intentionally so a request for "default" attaches to a host that was
        // launched with "Default": Chromium itself accepts either casing on Windows/macOS, and on Linux the user is
        // expected to specify the literal directory name. We err on the side of attaching rather than rejecting.
        if (requestedProfileDirectoryName is null ||
            string.Equals(existingProfileDirectoryName, requestedProfileDirectoryName, StringComparison.OrdinalIgnoreCase))
        {
            return;
        }

        throw new InvalidOperationException(
            string.Format(
                CultureInfo.CurrentCulture,
                BrowserMessageStrings.BrowserLogsTrackedBrowserProfileConflict,
                identity.UserDataRootPath,
                existingProfileDirectoryName ?? BrowserMessageStrings.BrowserLogsDefaultProfileName,
                requestedProfileDirectoryName));
    }

    private static string FormatDebugEndpoint(Uri? debugEndpoint) =>
        debugEndpoint?.ToString() ?? "private CDP pipe";

    private sealed class BrowserHostEntry(IBrowserHost host, string? profileDirectoryName, int ReferenceCount)
    {
        public IBrowserHost Host { get; } = host;

        public string? ProfileDirectoryName { get; } = profileDirectoryName;

        public int ReferenceCount { get; set; } = ReferenceCount;

View on GitHub (pinned to 25830f84bd)