nanocoai/nanoclaw · info

approval-pending

approval-pending

Error message

Approval request sent to admin. You will be notified of the result.

What it means

Not a failure: the guard returned `hold`, the dispatcher created a pending approval via requestApproval (title `CLI: <command>`), and the agent gets `approval-pending`. The command did not run; a human must approve or deny, and on approve the request is replayed with the approval row as a grant.

Source

Thrown at src/cli/dispatch.ts:165

      return err(req.id, 'handler-error', 'Session not found.');
    }
    const agentGroup = await getAgentGroup(ctx.agentGroupId);
    const agentName = agentGroup?.name ?? ctx.agentGroupId;

    const argSummary = Object.entries(req.args)
      .map(([k, v]) => `--${k} ${v}`)
      .join(' ');

    await requestApproval({
      session,
      agentName,
      action: 'cli_command',
      payload: { frame: { id: req.id, command: req.command, args: req.args }, callerContext: ctx },
      title: `CLI: ${req.command}`,
      question: `Agent "${agentName}" wants to run:\n\`ncl ${req.command}${argSummary ? ' ' + argSummary : ''}\``,
    });

    return err(req.id, 'approval-pending', 'Approval request sent to admin. You will be notified of the result.');
  }

  let parsed: unknown;
  try {
    parsed = cmd.parseArgs(req.args);
  } catch (e) {
    return err(req.id, 'invalid-args', errMsg(e));
  }

  try {
    let data = await cmd.handler(parsed, ctx);

    // Post-handler group-scope enforcement. Applies only to the auto-generated
    // `list` / `get` handlers (`cmd.generic`), which return raw DB rows carrying
    // the resource's `scopeField`:
    //   - `list` → drop rows that don't belong to the caller's agent group
    //              (covers `groups list`, where the generic list handler ignores
    //              the auto-filled `--id`)

View on GitHub (pinned to 294ef2aee8)

Solutions

  1. Wait for an approver (scoped admin → global admin → owner, per pickApprover) to action the card
  2. Check `ncl approvals list` / the approver DM to see or resolve the pending request
  3. Don't retry the command while a card is pending — it creates duplicate approvals
  4. If the action shouldn't need approval, adjust the guard policy for that command
Defensive patterns

Strategy: fallback

Validate before calling

const pending = await runNcl('approvals list --json').catch(() => []);
if (pending.some(a => a.payload?.frame?.command === myCommand)) {
  return 'already awaiting approval';
}

Try / catch

Treat code === 'approval-pending' as a terminal-for-now outcome: stop, notify the user, and resume on the approval result message — never retry in a loop.

Prevention

When it happens

Trigger: A group-scoped agent runs an approval-gated ncl verb (e.g. `groups update`, `groups config update --timezone`, self-mod-adjacent commands); any credentialed/privileged action whose guard policy is hold.

Common situations: Normal operation for privileged agent actions; agent retries the same command repeatedly and mints multiple pending cards; approver doesn't respond so the agent sees it 'hang' from its perspective.

Related errors


AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28). Data as JSON: /api/errors/1a4eadf62ab5562a. Report an issue: GitHub.