CloakHQ/CloakBrowser · error · UnsupportedHumanizeSelectorError

UnsupportedHumanizeSelectorError: {selector}

Error message

UnsupportedHumanizeSelectorError: {selector}

What it means

UnsupportedHumanizeSelectorError mapped from StealthStatus.Unsupported: the stealth DOM engine cannot resolve this selector shape, so the humanized locator path cannot run for it.

Source

Thrown at dotnet/src/CloakBrowser/Wrappers/LocatorHumanizer.cs:21

namespace CloakBrowser.Wrappers;

/// <summary>Humanized locator actions. Direct page.Locator selectors use the canonical isolated DOM world; unknown locator shapes retain the legacy Playwright path.</summary>
internal static class LocatorHumanizer
{
    private static double RemainingMs(double deadline) => Actionability.RemainingMs(deadline);

    private static async Task<IsolatedWorld> WorldAsync(HumanCursor cursor) =>
        await cursor.GetStealthAsync().ConfigureAwait(false) ?? throw new StealthWorldUnavailableError();

    internal static async Task<StealthSnapshot> SnapshotAsync(HumanCursor cursor, string selector)
    {
        var (status, snapshot) = await StealthDom.SnapshotAsync(await WorldAsync(cursor).ConfigureAwait(false), selector).ConfigureAwait(false);
        return status switch
        {
            StealthStatus.Ok when snapshot != null => snapshot.Value,
            StealthStatus.NotFound => throw new ElementNotAttachedError(selector),
            StealthStatus.Unsupported => throw new UnsupportedHumanizeSelectorError(selector),
            _ => throw new StealthEvaluationError(selector),
        };
    }

    internal static async Task EnsureActionableAsync(HumanCursor cursor, string selector,
        IReadOnlySet<string> checks, double timeout, bool force)
    {
        var world = await WorldAsync(cursor).ConfigureAwait(false);
        await Actionability.EnsureActionableAsync(cursor.Page, selector, checks, timeout, force, world).ConfigureAwait(false);
    }

    private static async Task<BoundingBox?> GetBoxAsync(
        IsolatedWorld world, string selector, double timeoutMs)
    {
        double deadline = System.Environment.TickCount64 + System.Math.Max(0, timeoutMs);
        var result = await StealthDom.BoxAsync(world, selector).ConfigureAwait(false);
        while ((result.Status == StealthStatus.NotFound || result.Status == StealthStatus.EvaluationFailed)
            && System.Environment.TickCount64 < deadline)

View on GitHub (pinned to d6bad5de26)

Solutions

  1. Convert the selector to plain CSS or XPath understood by the stealth DOM engine
  2. Use a stable data-testid CSS selector instead of Playwright pseudo-classes
  3. Fall back to the non-humanized Playwright path for exotic selectors

Example fix

# before
await page.locator("button:has-text('Submit')").human_click()

# after
await page.locator("button[type='submit']").human_click()
Defensive patterns

Strategy: type-guard

Validate before calling

bool supported = selector.All(c => char.IsLetterOrDigit(c)) && !selector.Contains(":has-text") && !selector.Contains(">>");

Type guard

static bool IsStealthSupportedSelector(string s) => !s.Contains(":") && !s.Contains(">>") && !s.StartsWith("text=");

Try / catch

catch (UnsupportedHumanizeSelectorError) { fall back to plain CSS equivalent or native Playwright path }

Prevention

When it happens

Trigger: Using selector syntax the isolated-world snapshot doesn't support — e.g. Playwright-specific engine selectors (:has-text, :visible, >> chained engines, internal: selectors) rather than plain CSS/XPath.

Common situations: Copying selectors from Playwright traces/codegen (which emit :text= and >> chains) into humanized locator calls.

Related errors


AI-assisted analysis of CloakHQ/CloakBrowser@d6bad5de26 (2026-08-28). Data as JSON: /api/errors/2f8b916469a90a8d. Report an issue: GitHub.