nanocoai/nanoclaw · error
agent group not found
Error message
agent group not found: ${agentGroupId} What it means
appendRunLog looks up the agent group in the central DB to resolve its folder under groups/. If getAgentGroup returns null the group id does not exist (never created, deleted, or typo'd), and the run log cannot be written because the target directory is unknown.
Solutions
- List existing groups (ncl groups list) and use the exact id.
- If the group was deleted but tasks remain, clean up or re-create the group before logging.
- Parameterize group ids from config rather than hardcoding them per environment.
Example fix
// before
await appendRunLog('my-group', series, 'ran');
// after
const groups = await listAgentGroups();
const g = groups.find(x => x.name === 'my-group');
await appendRunLog(g.id, series, 'ran'); Defensive patterns
Strategy: try-catch
Validate before calling
import { getAgentGroup } from './db/agent-groups';
const ag = await getAgentGroup(agentGroupId);
if (!ag) throw new Error(`unknown agent group: ${agentGroupId}`); Try / catch
try { await appendRunLog(groupId, series, msg); } catch (err) { if ((err as Error).message.startsWith('agent group not found')) { /* skip or re-resolve group */ } else throw err; } Prevention
- Resolve the group id once at startup and reuse it.
- Don't hardcode group ids across environments; load from config.
When it happens
Trigger: Calling appendRunLog/appendTaskLog/appendHostTaskNote with an agentGroupId that is not present in the agent_groups table — a stale id after the group was deleted, a copy-pasted id from another install, or a truncated id.
Common situations: Tasks outliving their agent group after deletion; scripts hardcoding group ids across environments; referencing a group by folder name or display name instead of its 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
- agent group " " has invalid runtime_tier " " — expected…
- Agent group not found
- Failed to append task run log
- --group is required
- invalid --recurrence
AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28).
Data as JSON: /api/errors/558163d2efcd2a8f.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/scheduling/run-log.ts:26
* (container/agent-runner poll-loop auto-append; delivery.ts routes it here)
*/
import fs from 'fs';
import { GROUPS_DIR } from '../../config.js';
import { resolveGroupTimezone } from '../../container-config.js';
import { getAgentGroup } from '../../db/agent-groups.js';
import { formatLocalStamp } from '../../timezone.js';
export async function appendRunLog(
agentGroupId: string,
series: string,
msg: string,
): Promise<{ series: string; timestamp: string; path: string }> {
// Charset guard is the security boundary: blocks path traversal and keeps
// the id safe as a filename. Callers resolve group scope before this.
if (!/^[a-z0-9-]+$/.test(series)) throw new Error(`invalid task id: ${series}`);
const ag = await getAgentGroup(agentGroupId);
if (!ag) throw new Error(`agent group not found: ${agentGroupId}`);
const timestamp = formatLocalStamp(new Date(), await resolveGroupTimezone(agentGroupId));
const dir = `${GROUPS_DIR}/${ag.folder}/tasks`;
const file = `${dir}/${series}.md`;
fs.mkdirSync(dir, { recursive: true });
fs.appendFileSync(file, `${timestamp} — ${msg}\n`);
return { series, timestamp, path: file };
}
export async function deleteRunLog(agentGroupId: string, series: string): Promise<void> {
if (!/^[a-z0-9-]+$/.test(series)) throw new Error(`invalid task id: ${series}`);
const ag = await getAgentGroup(agentGroupId);
if (!ag) throw new Error(`agent group not found: ${agentGroupId}`);
fs.rmSync(`${GROUPS_DIR}/${ag.folder}/tasks/${series}.md`, { force: true });
}
View on GitHub (pinned to 294ef2aee8)