NousResearch/hermes-agent · error · SubagentLifecycleError

Requested toolsets would broaden parent permissions.

Error message

Requested toolsets would broaden parent permissions.

What it means

Security validation from SubagentLifecycleManager._validate_request(): when the parent agent has an explicit enabled_toolsets set, the requested allowed_toolsets must be a subset of it. A child may never have toolsets the parent itself does not — the check prevents privilege escalation through subagent launching.

Source

Thrown at agent/subagent_lifecycle.py:538

                json.dumps(dict(request.metadata), sort_keys=True).encode()
            )
        except (TypeError, ValueError) as exc:
            raise SubagentLifecycleError("metadata must be JSON-serializable.") from exc
        if metadata_bytes > _MAX_METADATA_BYTES:
            raise SubagentLifecycleError("metadata exceeds 8192 bytes.")
        if request.allowed_toolsets:
            from toolsets import TOOLSETS

            unknown = set(request.allowed_toolsets) - set(TOOLSETS)
            if unknown:
                raise SubagentLifecycleError(
                    f"Unknown toolsets: {', '.join(sorted(unknown))}."
                )
            enabled = getattr(parent, "enabled_toolsets", None)
            if enabled is not None and not set(request.allowed_toolsets).issubset(
                set(enabled)
            ):
                raise SubagentLifecycleError(
                    "Requested toolsets would broaden parent permissions."
                )

View on GitHub (pinned to c896c09c42)

Solutions

  1. Intersect the request with the parent's live set: pass allowed_toolsets=[t for t in wanted if t in (parent.enabled_toolsets or wanted)].
  2. Widen the parent's own toolset configuration (hermes tools or tools.<platform>.enabled in config.yaml) if the child genuinely needs more — a deliberate operator decision, not a per-launch one.
  3. Drop the allowed_toolsets field entirely so the child inherits the parent's enabled set.

Example fix

# before
request = SubagentLaunchRequest(goal=g, allowed_toolsets=["terminal", "file"])
# parent (messaging) only has ["search", "file"] -> rejected

# after
enabled = set(parent.enabled_toolsets or [])
request = SubagentLaunchRequest(
    goal=g,
    allowed_toolsets=[t for t in ("terminal", "file") if not enabled or t in enabled],
)
Defensive patterns

Strategy: validation

Validate before calling

enabled = set(getattr(parent, "enabled_toolsets", None) or [])
if enabled:
    wanted = [t for t in requested if t in enabled]
else:
    wanted = requested  # parent unrestricted
request = SubagentLaunchRequest(goal=goal, allowed_toolsets=wanted)

Try / catch

try:
    manager.launch(request)
except SubagentLifecycleError as exc:
    if "broaden parent permissions" in str(exc):
        request = dataclasses.replace(request, allowed_toolsets=None)  # inherit parent
        handle = manager.launch(request)
    else:
        raise

Prevention

When it happens

Trigger: A parent restricted to ["search"] asked to launch a child with allowed_toolsets=["terminal", "search"]; platform-scoped agents (e.g. messaging) requesting web/file toolsets they were not granted; a request template built for a full-CLI parent reused under a restricted profile.

Common situations: Running the same plugin across CLI (broad tools) and gateway/messaging (narrow tools) contexts; profile or per-platform tool restrictions in config.yaml (tools.<platform>.enabled); least-privilege setups where the parent was deliberately narrowed.

Related errors


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/a2ba5aeda0a10b50. Report an issue: GitHub.