nanocoai/nanoclaw · warning
No approval handler registered — row dropped
Error message
No approval handler registered — row dropped
What it means
An approval was approved, but no handler is registered for its action string (getApprovalHandler returned null). The pending row is deleted and the requester is notified that the approval cannot be applied.
Source
Thrown at src/modules/approvals/response-handler.ts:108
}
if (!(await transitionPendingApprovalStatus(approval.approval_id, 'pending', 'approved'))) return;
// Approved — dispatch to the module that registered for this action.
const notify = (text: string): Promise<void> =>
writeSessionMessage(session.agent_group_id, session.id, {
id: `appr-note-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
kind: 'chat',
timestamp: new Date().toISOString(),
platformId: session.agent_group_id,
channelType: 'agent',
threadId: null,
content: JSON.stringify({ text, sender: 'system', senderId: 'system' }),
});
const handler = getApprovalHandler(approval.action);
if (!handler) {
log.warn('No approval handler registered — row dropped', {
approvalId: approval.approval_id,
action: approval.action,
});
await notify(`Your ${approval.action} was approved, but no handler is installed to apply it.`);
await deletePendingApproval(approval.approval_id);
await notifyApprovalResolved({ approval, session, outcome: 'approve', userId });
await wakeContainer(session);
return;
}
const payload = JSON.parse(approval.payload);
try {
await handler({ session, payload, approval, userId, notify });
log.info('Approval handled', { approvalId: approval.approval_id, action: approval.action, userId });
} catch (err) {
log.error('Approval handler threw', { approvalId: approval.approval_id, action: approval.action, err });
await notify(
`Your ${approval.action} was approved, but applying it failed: ${err instanceof Error ? err.message : String(err)}.`,View on GitHub (pinned to 294ef2aee8)
Solutions
- Identify the action name from the log and verify the module that registers its handler is installed and imported
- Re-request the approval so a fresh row with a supported action is created
- Clean stale pending_approvals rows left over from an older version
Defensive patterns
Strategy: validation
Validate before calling
if (!getApprovalHandler(action)) {
throw new Error(`No handler for approval action '${action}' — register it before requesting approval`);
} Type guard
const isRegisteredAction = (a: string): boolean => getApprovalHandler(a) !== null;
Prevention
- Register all approval handlers in one barrel imported at startup
- On upgrade, drain or migrate stale pending_approvals rows
When it happens
Trigger: A pending_approval row exists with an 'action' value whose handler was never registered at startup; a plugin/module that registers the handler failed to load; action renamed between versions leaving stale rows.
Common situations: Upgrading NanoClaw where an action was renamed; a skill-installed module that registers approval handlers missing or failed to import; hand-inserted pending rows.
Related errors
- --approver is required
- Unknown system action
- reject-with-reason: cannot reach approver, finalizing plain
- Ignoring unauthorized approval response
AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28).
Data as JSON: /api/errors/6cda2af96e9db80b.
Report an issue: GitHub.