openclaw/openclaw · error

Dialog "${dialogId}" is not pending.

Error message

Dialog "${dialogId}" is not pending.

What it means

Thrown by resolvePendingDialogForResponse (extensions/browser/src/browser/pw-session-dialogs.ts:158). The caller supplied a dialogId, but no entry in state.pendingDialogs has a matching id. The targeted dialog was already responded to, was auto-dismissed (e.g. by navigation or armed response expiry), or the id is simply wrong.

Source

Thrown at extensions/browser/src/browser/pw-session-dialogs.ts:158

    return;
  }
  if (armed) {
    clearArmedDialogResponse(pageState);
  }
  abortActionsBlockedByDialog(pageState);
}

export function resolvePendingDialogForResponse(params: {
  state: PageState;
  dialogId?: string;
}): PendingObservedDialog {
  const dialogId = normalizeOptionalString(params.dialogId);
  if (dialogId) {
    const found = params.state.pendingDialogs.find((dialog) => dialog.id === dialogId);
    if (found) {
      return found;
    }
    throw new Error(`Dialog "${dialogId}" is not pending.`);
  }
  if (params.state.pendingDialogs.length === 1) {
    return expectDefined(params.state.pendingDialogs.at(0), "single pending browser dialog");
  }
  if (params.state.pendingDialogs.length > 1) {
    throw new Error("Multiple dialogs are pending; pass dialogId.");
  }
  throw new Error("No dialog is pending.");
}

/** Respond to a pending observed dialog on a page. */

View on GitHub (pinned to 01804a7531)

Solutions

  1. Re-snapshot page state and read the current pendingDialogs; respond with a live dialogId.
  2. If exactly one dialog is pending, omit dialogId and let the resolver pick it.
  3. Treat 'not pending' as a no-op success if the dialog was already handled.

Example fix

// before: stale dialogId
await respondDialog({ dialogId: oldId, accept: true });

// after: pick a live dialog
const { pendingDialogs } = await snapshot(state);
if (pendingDialogs.length === 1) {
  await respondDialog({ accept: true }); // omit dialogId
} else if (pendingDialogs.length) {
  await respondDialog({ dialogId: pendingDialogs[0].id, accept: true });
}
Defensive patterns

Strategy: validation

Validate before calling

// Before responding, confirm the dialogId is still pending.
const { pendingDialogs } = await snapshotPageState(page);
if (dialogId && !pendingDialogs.some((d) => d.id === dialogId)) {
  // dialog already gone; treat as no-op instead of erroring
  return { ok: true, alreadyClosed: true };
}
await respondDialog({ dialogId, accept });

Type guard

function isPendingDialogId(state, id): boolean {
  return typeof id === "string" && state.pendingDialogs.some((d) => d.id === id);
}

Try / catch

try {
  await respondDialog({ dialogId, accept: true });
} catch (err) {
  if (err.message === `Dialog "${dialogId}" is not pending.`) {
    // already handled or dismissed; safe to continue
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Responding to a dialog with a dialogId captured from an older snapshot; calling respond twice for the same dialog; the page dismissed the dialog (navigation, armed response fired, or it was a transient alert) between snapshot and response; typo'd dialogId.

Common situations: Race between an armed dialog response (armedDialogResponse) auto-settling and an explicit respond call; concurrent respond attempts; snapshot taken before the dialog was promoted into pendingDialogs.

Related errors


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