nanocoai/nanoclaw · error · Error
${name} must be one of: ${allowed.join(', ')}
Error message
${name} must be one of: ${allowed.join(', ')} What it means
Wiring creation validates enum columns (CREATE_ENUMS: ignored_message_policy drop|accumulate, session_mode shared|per-thread|agent-shared) and throws listing the allowed values when a supplied value is not in the set.
Source
Thrown at src/cli/resources/wirings.ts:216
// Idempotent: a wiring for this pair already exists → return it
// (defaults/validation/side-effects are skipped — nothing new is written).
const existing = await getMessagingGroupAgentByPair(mgId, agId);
if (existing) return existing;
// Pass-1 parity: only defined keys enter `values` (an unset
// engage_pattern stays absent → column NULL), enums validated.
const values: Record<string, unknown> = {
id: randomUUID(),
messaging_group_id: mgId,
agent_group_id: agId,
created_at: new Date().toISOString(),
};
for (const [name, allowed] of Object.entries(CREATE_ENUMS)) {
const v = args[name];
if (v === undefined) continue;
if (!allowed.includes(String(v))) {
throw new Error(`${name} must be one of: ${allowed.join(', ')}`);
}
values[name] = v;
}
if (args.engage_pattern !== undefined) values.engage_pattern = args.engage_pattern;
if (args.threads !== undefined) values.threads = args.threads;
if (args.priority !== undefined) values.priority = Number(args.priority);
// Pass-2 parity: context-aware defaults + cross-column validation.
const mg = await requireMessagingGroup(values.messaging_group_id);
if (values.threads !== undefined) values.threads = normalizeThreads(values.threads);
const channelKey = mg.instance ?? mg.channel_type;
// Undeclared (stale) channels: leave engage_mode unset so the static
// 'mention' default applies afterwards — a trunk update alone must not
// change ncl's creation defaults for adapters without a declaration.
if (values.engage_mode === undefined) {
if (hasDeclaredChannelDefaults(channelKey, mg.channel_type)) {
const ag = await getAgentGroup(String(values.agent_group_id));View on GitHub (pinned to 294ef2aee8)
Solutions
- Use an allowed value from the message: session_mode = shared|per-thread|agent-shared; ignored_message_policy = drop|accumulate
- Check `ncl wirings help` for current options
Example fix
# before ncl wirings create ... --session-mode group # after ncl wirings create ... --session-mode agent-shared
Defensive patterns
Strategy: validation
Validate before calling
const ENUMS = { ignored_message_policy:['drop','accumulate'], session_mode:['shared','per-thread','agent-shared'] };
for (const [k, allowed] of Object.entries(ENUMS)) {
if (v[k] !== undefined && !allowed.includes(String(v[k]))) throw new Error(`${k} must be one of: ${allowed.join(', ')}`);
} Type guard
function isValidWiringEnum(k: string, v: string): boolean {
const allowed: Record<string,string[]> = {
ignored_message_policy: ['drop','accumulate'],
session_mode: ['shared','per-thread','agent-shared'],
};
return !allowed[k] || allowed[k].includes(v);
} Prevention
- Copy enum values from `ncl wirings help`, not memory
When it happens
Trigger: ncl wirings create --session-mode group or --ignored-message-policy skip — any value outside the declared enums.
Common situations: Guessing enum spellings ('isolate' for session_mode, 'ignore' for ignored_message_policy) or stale docs from an older version with different values.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- messaging group not found: ${id}
- provide --messaging-group-id, or --channel-type and --platfo
- no messaging group for ${channelType} ${platformId} — create
- provide --agent-group-id or --agent-group <folder>
- no agent group "${ref}" (by id or folder)
AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28).
Data as JSON: /api/errors/1c4ecd26cb24b922.
Report an issue: GitHub.