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
- Wait for an approver (scoped admin → global admin → owner, per pickApprover) to action the card
- Check `ncl approvals list` / the approver DM to see or resolve the pending request
- Don't retry the command while a card is pending — it creates duplicate approvals
- 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
- Never auto-retry approval-gated commands; check `approvals list` first
- Ensure at least one approver role exists (owner/admin) or cards go nowhere
- Design agent prompts to inform the user a card was sent
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
- Provide --apt <pkg> or --npm <pkg>
- Provide --host <host-path> and --container <container-path>
- messaging group not found: ${id}
- --threads must be true or false, got "${v}"
- provide --messaging-group-id, or --channel-type and --platfo
AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28).
Data as JSON: /api/errors/1a4eadf62ab5562a.
Report an issue: GitHub.