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
- 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)].
- 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.
- 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
- Compute the requested set as an intersection with parent.enabled_toolsets before launch.
- Omit allowed_toolsets to have the child inherit the parent's set — never wider.
- If a child legitimately needs more tools, widen the parent via hermes tools / config.yaml as an operator decision.
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
- Per-tool blocking is not supported; use allowed_toolsets. He
- Unknown toolsets: {', '.join(sorted(unknown))}.
- Malformed subagent handle.
- No active Hermes parent session is available.
- parent_session_id does not match the active session.
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/a2ba5aeda0a10b50.
Report an issue: GitHub.