openclaw/openclaw · error · BrowserTargetAmbiguousError

ambiguous browser tab reference

Error message

ambiguous browser tab reference

What it means

Thrown by BrowserTargetAmbiguousError (HTTP 409) in the listTabs default-selection path when resolveById returns the sentinel 'AMBIGUOUS'. This happens when a non-exact tab reference (label or alias) matches more than one candidate tab. The default error message is 'ambiguous browser tab reference'.

Source

Thrown at extensions/browser/src/browser/server-context.selection.ts:217

      const last = stickyTargetId ?? "";
      const lastResolved = last ? resolveById(last, { exactTargetId: true }) : null;
      if (lastResolved && lastResolved !== "AMBIGUOUS") {
        return lastResolved;
      }
      // Sticky selection is an identity promise. If it disappears without a proven
      // alias migration, require a fresh explicit choice instead of guessing a tab.
      if (last) {
        return null;
      }
      // Prefer a real page tab first (avoid service workers/background targets).
      const page = candidates.find((t) => (t.type ?? "page") === "page");
      return page ?? candidates.at(0) ?? null;
    };

    const chosen = targetId ? resolveById(targetId) : pickDefault();

    if (chosen === "AMBIGUOUS") {
      throw new BrowserTargetAmbiguousError();
    }
    if (!chosen) {
      throw new BrowserTabNotFoundError({ input: targetId ?? stickyTargetId });
    }
    runtime.lastTargetId = chosen.targetId;
    return chosen;
  };

  const resolveTargetIdOrThrow = async (
    targetId: string,
    options?: BrowserTabTargetOptions,
  ): Promise<string> => {
    const tabs = await listTabs(options);
    if (options?.exactTargetId) {
      const exactTarget = tabs.find((tab) => tab.targetId === targetId);
      if (!exactTarget) {
        throw new BrowserTabNotFoundError({ input: targetId });
      }

View on GitHub (pinned to 01804a7531)

Solutions

  1. Use action=tabs to list current tabs and pass a more specific suggestedTargetId, tabId, label, or raw targetId.
  2. Pass exactTargetId:true to bypass alias resolution and match the raw targetId directly.
  3. Close duplicate tabs so the alias is unique.
  4. Use a raw targetId (longest, most specific identifier) instead of a short label.

Example fix

// before: ambiguous label
await browser.tab('chat');  // matches 3 tabs
// after: disambiguate with raw targetId from action=tabs
await browser.tab('A1B2C3D4...targetId', { exactTargetId: true });
Defensive patterns

Strategy: validation

Validate before calling

// Resolve the tab id against current tabs before acting; detect ambiguity upfront
async function resolveUniquely(targetId: string, tabs): Promise<string | null> {
  const matches = tabs.filter(t => t.label === targetId || t.alias === targetId);
  if (matches.length > 1) return null; // ambiguous
  return matches[0]?.targetId ?? null;
}

Type guard

import { BrowserTargetAmbiguousError } from './errors';
function isTabAmbiguous(err: unknown): err is BrowserTargetAmbiguousError {
  return err instanceof BrowserTargetAmbiguousError;
}

Try / catch

try {
  await browser.tab(targetId);
} catch (err) {
  if (err instanceof BrowserTargetAmbiguousError) {
    const tabs = await browser.tabs();
    // ask the user / caller to disambiguate using a raw targetId
    throw new Error(`ambiguous; candidates: ${tabs.map(t => t.targetId).join(', ')}`, { cause: err });
  }
  throw err;
}

Prevention

When it happens

Trigger: listTabs() called with a targetId that resolves via resolveTargetIdFromTabs which returns { ok:false, reason:'ambiguous' }, and no exactTargetId override was supplied.

Common situations: Two tabs share the same label/alias; a shorthand matches multiple tab titles; positional/tabId alias collides after tabs were duplicated; the user opened two identical pages.

Related errors


AI-assisted analysis of openclaw/openclaw@01804a7531 (2026-08-12). Data as JSON: /api/errors/410dd5bf9af3929f. Report an issue: GitHub.