nanocoai/nanoclaw · error · Error

group not found: ${id}

Error message

group not found: ${id}

What it means

`ncl groups delete --id <id>` was given an id that matches no row in the agent_groups table. The handler explicitly checks existence first (preserving genericDelete's not-found semantics) before attempting the FK-ordered cascade delete in a transaction.

Source

Thrown at src/cli/resources/groups.ts:220

          ? formatRestampResult(data as RestampResult)
          : JSON.stringify(localizeIsoTimestamps(data), null, 2),
    },
    delete: {
      access: 'approval',
      description:
        'Delete an agent group and its dependent rows (sessions, destinations, approvals, role grants, ' +
        'memberships, channel wirings). FK-ordered cascade in a single transaction. ' +
        'Use --id <group-id>. Out of scope: killing running containers, on-disk cleanup of groups/<folder>/ and data/v2-sessions/<group-id>/. ' +
        'The leftover groups/<folder>/ blocks re-creating a group under the same folder name until it is moved or removed.',
      handler: async (args) => {
        const id = args.id as string;
        if (!id) throw new Error('--id is required');
        const db = getDb();

        // Verify the group exists before doing anything — preserves the
        // genericDelete behaviour of throwing "not found" for unknown IDs.
        const exists = await db.get('SELECT 1 FROM agent_groups WHERE id = ? LIMIT 1', id);
        if (!exists) throw new Error(`group not found: ${id}`);

        const hasAgentDestinations = await hasTable(db, 'agent_destinations');
        const hasPendingApprovals = await hasTable(db, 'pending_approvals');

        // FK-ordered cascade. The async driver transaction rolls
        // back the whole thing if any statement throws (e.g. an FK constraint
        // we missed), so the central DB stays consistent. The `removed` counts
        // are sourced from each DELETE's `changes` so they describe exactly
        // what the transaction did, not a separate pre-flight snapshot.
        const removed = await db.transaction(async () => {
          const counts = {
            sessions: 0,
            pending_questions: 0,
            pending_approvals: 0,
            agent_destinations_owned: 0,
            agent_destinations_pointing: 0,
            pending_sender_approvals: 0,
            pending_channel_approvals: 0,

View on GitHub (pinned to 294ef2aee8)

Solutions

  1. Check what exists: `ncl groups list` — if the group is gone, the delete already succeeded; treat this as done
  2. If you meant a different group, copy the exact id (ag-<uuid>) from the list output and retry
  3. In scripts, guard with a existence check or catch the not-found message and exit 0

Example fix

# before
ncl groups delete --id ag-old-id
# after
ncl groups list   # confirm current ids
ncl groups delete --id ag-actual-uuid
# script-safe:
ncl groups delete --id "$ID" 2>/dev/null || true
Defensive patterns

Strategy: try-catch

Validate before calling

const row = await db.get('SELECT 1 FROM agent_groups WHERE id = ?', id);
if (!row) { /* already gone — treat as success */ }

Type guard

const exists = (r: unknown): r is { '1': number } => !!r;

Try / catch

try { await deleteGroup(id) } catch (e) { if (e instanceof Error && e.message.startsWith('group not found:')) return; /* idempotent no-op */ throw e; }

Prevention

When it happens

Trigger: Passing a stale, mistyped, or already-deleted group id, e.g. `ncl groups delete --id ag-typo` or re-running a delete script after the group was already removed.

Common situations: Re-running an idempotency-intended delete script (delete is not idempotent — it throws instead of no-op'ing); copy/paste truncating the uuid; referencing a group deleted by another operator or by a migration; using the folder name instead of the ag-<uuid> id.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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