nanocoai/nanoclaw · error
handler-error
handler-error
Error message
session not found: ${req.args.id} What it means
A group-scoped agent asked for `sessions-get` or `sessions-history` with a session id that either doesn't exist or belongs to a different agent group. The check is fail-closed: both cases return the same 'session not found' so agents can't probe UUIDs that exist in other groups.
Source
Thrown at src/cli/dispatch.ts:112
if (req.args.help !== true && (req.command === 'wirings-get' || req.command === 'wirings-update')) {
const wiring = await getMessagingGroupAgentByPair(ctx.messagingGroupId, ctx.agentGroupId);
if (!wiring) return err(req.id, 'forbidden', 'Wiring not found for this conversation.');
fill.id = wiring.id;
}
req = { ...req, args: { ...req.args, ...fill } };
// Fail-closed pre-handler check for sessions-get/-history: returns
// "not found" regardless of whether the UUID exists in another group,
// preventing an existence oracle across group boundaries. (history
// also self-scopes in its handler — this is defense-in-depth.)
if (
cmd.resource === 'sessions' &&
(req.command === 'sessions-get' || req.command === 'sessions-history') &&
req.args.id
) {
const s = await getSession(req.args.id as string);
if (!s || s.agent_group_id !== ctx.agentGroupId) {
return err(req.id, 'handler-error', `session not found: ${req.args.id}`);
}
}
}
}
const decision = await guard(commandGuard(cmd.name), {
actor: actorFor(ctx),
payload: req.args,
grant: opts.grant ?? null,
});
if (decision.effect === 'deny') {
return err(req.id, 'forbidden', decision.reason);
}
// `--help` interception: answer with the command's generated help instead of
// executing. Placed after the guard's deny (a group-scoped agent can't probe
// forbidden resources) and BEFORE hold execution — asking for help on anView on GitHub (pinned to 294ef2aee8)
Solutions
- List this group's own sessions: `ncl sessions list` (auto-scoped) and use one of those ids
- Check the id is a complete UUID with no whitespace/quotes
- If cross-group access is genuinely needed, an operator sets `ncl groups config update --cli-scope global` (approval-gated) or runs it host-side
Defensive patterns
Strategy: validation
Validate before calling
const sessions = await runNcl('sessions list --json'); // auto-scoped to own group
const ok = sessions.some(s => s.id === targetId);
if (!ok) throw new Error('session id not in this group'); Type guard
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
function isUuid(v: unknown): v is string { return typeof v === 'string' && UUID_RE.test(v); } Try / catch
Treat 'session not found' as terminal for that id — don't retry with variations; re-list sessions instead.
Prevention
- Always source session ids from this group's own `sessions list` output
- Validate UUID shape before sending
- Don't assume global visibility under cli_scope group
When it happens
Trigger: Agent passes a session id from another group, a malformed/truncated UUID, or a stale id from a deleted session; also when copy-pasting an id out of `ncl sessions list` output of a different group.
Common situations: Agent hallucinates or truncates a UUID; session was cleaned up by the sweep; operator scoped the agent to `group` while the agent assumed global visibility.
Related errors
- forbidden
- 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}"
AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28).
Data as JSON: /api/errors/a9b6d7944727c895.
Report an issue: GitHub.