nanocoai/nanoclaw · warning

Stored skill selection is not "all" or a string list; inlini

Error message

Stored skill selection is not "all" or a string list; inlining every skill

What it means

The `skills` column for an agent group was expected to be the JSON string `"all"` or a JSON array of skill-name strings, but the stored value parses to something else (or fails to parse). The parser falls back to `'all'`, inlining every skill into the container.

Source

Thrown at src/container-config.ts:351

 * match and silently drop skills.
 *
 * The single reading of this column. `configFromDb` used to cast it instead,
 * which threw on a corrupt row before the composer's tolerance could apply:
 * every spawn failed, and `wakeContainer`'s retry contract darkened the group.
 * Two readings that must agree is also how the document ends up teaching a
 * skill the agent was never given.
 */
export function parseSkillSelection(raw: string | undefined, groupName: string): string[] | 'all' {
  if (raw === undefined) return 'all';
  let parsed: unknown;
  try {
    parsed = JSON.parse(raw);
  } catch {
    parsed = undefined;
  }
  if (parsed === 'all') return 'all';
  if (Array.isArray(parsed) && parsed.every((n) => typeof n === 'string')) return parsed;
  log.warn('Stored skill selection is not "all" or a string list; inlining every skill', { group: groupName });
  return 'all';
}

/** Build a `ContainerConfig` from a DB row + agent group identity. */
export function configFromDb(row: ContainerConfigRow, group: AgentGroup): ContainerConfig {
  return {
    mcpServers: sanitizeStoredMcpServers(JSON.parse(row.mcp_servers), group.name),
    packages: {
      apt: JSON.parse(row.packages_apt) as string[],
      npm: JSON.parse(row.packages_npm) as string[],
    },
    imageTag: row.image_tag ?? undefined,
    additionalMounts: JSON.parse(row.additional_mounts) as AdditionalMountConfig[],
    skills: parseSkillSelection(row.skills, group.name),
    provider: row.provider ?? undefined,
    groupName: group.name,
    assistantName: row.assistant_name ?? group.name,
    agentGroupId: group.id,

View on GitHub (pinned to 294ef2aee8)

Solutions

  1. Fix the stored value: `ncl groups config update --skills all` or a proper JSON array string `'["skill-a"]'`
  2. Inspect the row: `pnpm exec tsx scripts/q.ts data/v2.db "select skills from container_configs"`
  3. Verify which skills get inlined after the fix

Example fix

// before (stored): skills = main
// after (stored): skills = "[\"main\"]"
Defensive patterns

Strategy: validation

Validate before calling

function isValidSkills(raw: string): boolean {
  try {
    const p = JSON.parse(raw);
    return p === 'all' || (Array.isArray(p) && p.every((n) => typeof n === 'string'));
  } catch { return false; }
}

Type guard

function isSkillSelection(v: unknown): v is 'all' | string[] {
  return v === 'all' || (Array.isArray(v) && v.every((n) => typeof n === 'string'));
}

Prevention

When it happens

Trigger: `configFromDb`/`selectedSkills`/`parseSkillSelection` reading a `skills` value like `["a", 1]`, `"main"`, `true`, or malformed JSON such as `['a','b']`.

Common situations: Manually editing the container_configs.skills column with non-JSON syntax; an older write path storing a bare string; a CLI flag writing unquoted values.

Related errors


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