Skip to content

bug(subagents): agent named constructor breaks all subagent calls with "overlay.add is not iterable" #3258

Open

Description

@kitomc

Before submitting

  • I searched open and closed issues and did not find a report of this problem.
  • I reviewed this report and removed credentials, tokens, private paths, hostnames, and other sensitive data.

Problem

Defining an agent whose name matches an Object.prototype member (for example constructor) breaks the whole subagent runtime. Every subagent_run and even subagent_list_agents fails with overlay.add is not iterable, for every agent, not only the offending one.

Root cause: discoverAgents in lib/agents-config.ts looks up the tool overlay with overlays.entries[parsed.name]. entries is a plain object built in loadToolOverlays (lib/agent-tool-overlay.ts), so for parsed.name === "constructor" the lookup returns the inherited Object.prototype.constructor function instead of undefined. applyToolOverlay only guards overlay === undefined, then spreads overlay.add, which is undefined on that function, and throws. Because the throw happens while discovering all agents, no agent can be listed or launched.

Steps to reproduce

  1. Create an agent file agents/constructor.md in the agent home with frontmatter name: constructor and any valid tools list. No tools.json overlay is needed.
  2. Start a session and call subagent_list_agents, or subagent_run with any other agent (for example gentle-ai-worker or gentle-ai-explore).
  3. The call fails with overlay.add is not iterable.

Minimal equivalent in code:

const entries: Record<string, { add: string[]; remove: string[] }> = {};
const overlay = entries["constructor"]; // Object.prototype.constructor, not undefined
[...overlay.add]; // TypeError: overlay.add is not iterable

Other names that hit the same path: toString, valueOf, hasOwnProperty, __proto__.

Expected and actual behavior

Expected: an agent with no overlay entry gets its declared tools unchanged, whatever its name; at worst a single invalid agent is reported in errors without affecting the others.

Actual: discovery throws, so every subagent tool call in the session fails with overlay.add is not iterable and no task is created.

Suggested fix: use an own-property lookup, for example Object.hasOwn(overlays.entries, parsed.name) ? overlays.entries[parsed.name] : undefined in discoverAgents, and/or build the overlay maps with Object.create(null) (this also protects the entries[name] = ... writes against a __proto__ key coming from a tools.json file). A regression test in tests/agent-tool-overlay.test.ts that discovers an agent named constructor without an overlay would pin it.

gentle-pi version

4.8.0

Pi version

1.5.2

Operating system

Windows 11 Pro (10.0.26200)

Relevant logs or error output (optional)

overlay.add is not iterable

Returned by subagent_run (agents gentle-ai-worker, gentle-ai-explore) and by subagent_list_agents; subagent_list_tasks reports "No subagent tasks in this session", confirming the failure happens before any task is created.

Activity

  1. kitomc commented on Nov 14, 2026

    @kitomc
    Author

    Confirming the root cause with a real run, plus a workaround.

    I ran gentle-pi 4.8.0's own discoverAgents (I copied lib/ to a temp directory, because Node refuses type stripping under node_modules) against a real agent home with 23 agents, one of them named constructor. It throws overlay.add is not iterable.

    After renaming that one agent to revision-max-constructor (the name: field of its file plus its keys in subagents.json, models.json and profiles.json), the same call loads all 23 agents with no errors or notices. subagent_list_agents and subagent_run work again in the running session, without a restart.

    So the defect is confirmed. lib/agents-config.ts:242 does overlays.entries[parsed.name] on a plain object, and applyToolOverlay in lib/agent-tool-overlay.ts only guards overlay === undefined. An agent named after an Object.prototype member (constructor, toString, valueOf, hasOwnProperty) gets the inherited function instead of undefined, and the spread of overlay.add throws.

    Workaround: do not name an agent constructor.

    The suggested fix is unchanged: use Object.hasOwn(overlays.entries, parsed.name) ? overlays.entries[parsed.name] : undefined, and/or build the overlay maps with Object.create(null), plus a regression test that discovers an agent named constructor without an overlay.

    Environment: gentle-pi 4.8.0, Pi 1.5.2, Windows 11.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions