vercel-labs/agent-browser · error

Provide at least one of: selector, text, urlPattern, loadSta

Error message

Provide at least one of: selector, text, urlPattern, loadState, jsCondition, timeMs.

What it means

The eve 'wait_for' tool builds a list of waits from six optional condition fields (selector, text, urlPattern, loadState, jsCondition, timeMs); timeoutMs is a modifier, not a condition. If every condition field is undefined the waits array is empty and execute() throws this message instead of running a pointless CLI call. Blank strings count as absent because optionalCondition preprocesses them to undefined.

Source

Thrown at packages/@agent-browser/eve/extension/tools/wait_for.ts:74

    }
    if (selector !== undefined) {
      waits.push({ args: ["wait", selector], condition: `element ${selector}` });
    }
    if (text !== undefined) {
      waits.push({ args: ["wait", "--text", text], condition: `text "${text}"` });
    }
    if (urlPattern !== undefined) {
      waits.push({ args: ["wait", "--url", urlPattern], condition: `url ${urlPattern}` });
    }
    if (jsCondition !== undefined) {
      waits.push({ args: ["wait", "--fn", jsCondition], condition: `js ${jsCondition}` });
    }
    if (timeMs !== undefined) {
      // A fixed delay is its own duration; --timeout would override it.
      waits.push({ args: ["wait", String(timeMs)], condition: `${timeMs}ms delay`, isDelay: true });
    }
    if (waits.length === 0) {
      throw new Error(
        "Provide at least one of: selector, text, urlPattern, loadState, jsCondition, timeMs.",
      );
    }
    const cap = timeoutMs ?? 10_000;
    const outcomes: WaitOutcome[] = [];
    for (const wait of waits) {
      const args = wait.isDelay ? wait.args : [...wait.args, "--timeout", String(cap)];
      outcomes.push(await runWait(ctx, args, wait.condition));
    }
    return outcomes.length === 1 ? outcomes[0] : outcomes;
  },
});

async function runWait(
  ctx: BrowserToolContext,
  args: readonly string[],
  condition: string,
): Promise<WaitOutcome> {

View on GitHub (pinned to 548b159b30)

Solutions

  1. Add at least one condition, e.g. tools.waitFor({ selector: '#done' }) or tools.waitFor({ timeMs: 1000 })
  2. For a plain delay use timeMs
  3. If you only wanted the default page-load wait, skip the tool entirely — navigation already waits for load

Example fix

// before
await tools.waitFor({ timeoutMs: 5000 });

// after
await tools.waitFor({ selector: "#done", timeoutMs: 5000 });
Defensive patterns

Strategy: validation

Validate before calling

const hasCondition =
  [input.selector, input.text, input.urlPattern, input.loadState, input.jsCondition, input.timeMs]
    .some((v) => v !== undefined && v !== "");
if (!hasCondition) {
  throw new Error("wait_for needs at least one condition; use timeMs for a plain delay");
}

Type guard

function hasWaitCondition(i: Record<string, unknown>): boolean {
  return ["selector", "text", "urlPattern", "loadState", "jsCondition", "timeMs"]
    .some((key) => i[key] !== undefined);
}

Prevention

When it happens

Trigger: Calling wait_for with only timeoutMs; passing empty-string conditions (they are preprocessed away); models sending { } as a 'just wait' call without timeMs.

Common situations: Agent templates that always call wait_for after navigation; optional fields stripped by JSON round-trips; copy-pasted calls where the condition variable was empty.

Related errors


AI-assisted analysis of vercel-labs/agent-browser@548b159b30 (2026-08-16). Data as JSON: /api/errors/a6be94bdc628ba24. Report an issue: GitHub.