{"record":{"id":"649ce5715ec6befd","repo":"NousResearch/hermes-agent","slug":"role-must-be-leaf-or-orchestrator","errorCode":null,"errorMessage":"role must be 'leaf' or 'orchestrator'.","messagePattern":"role must be 'leaf' or 'orchestrator'\\.","errorType":"exception","errorClass":"SubagentLifecycleError","httpStatus":null,"severity":"error","filePath":"agent/subagent_lifecycle.py","lineNumber":505,"sourceCode":"    def _validate_request(request: SubagentLaunchRequest, parent: Any) -> None:\n        if (\n            not isinstance(request, SubagentLaunchRequest)\n            or not isinstance(request.goal, str)\n            or not request.goal.strip()\n            or len(request.goal) > _MAX_GOAL_CHARS\n        ):\n            raise SubagentLifecycleError(\n                \"goal must be a non-empty string of at most 16000 characters.\"\n            )\n        if request.context is not None and (\n            not isinstance(request.context, str)\n            or len(request.context) > _MAX_CONTEXT_CHARS\n        ):\n            raise SubagentLifecycleError(\n                \"context must be a string of at most 32000 characters.\"\n            )\n        if request.role not in {\"leaf\", \"orchestrator\"}:\n            raise SubagentLifecycleError(\"role must be 'leaf' or 'orchestrator'.\")\n        if request.timeout_seconds is not None:\n            raise SubagentLifecycleError(\n                \"Per-launch timeout is not supported; configure delegation timeout explicitly.\"\n            )\n        if request.working_directory is not None:\n            raise SubagentLifecycleError(\n                \"working_directory is not supported because Hermes delegates use isolated task environments.\"\n            )\n        if request.blocked_tools:\n            raise SubagentLifecycleError(\n                \"Per-tool blocking is not supported; use allowed_toolsets. Hermes always blocks unsafe child tools.\"\n            )\n        try:\n            metadata_bytes = len(\n                json.dumps(dict(request.metadata), sort_keys=True).encode()\n            )\n        except (TypeError, ValueError) as exc:\n            raise SubagentLifecycleError(\"metadata must be JSON-serializable.\") from exc","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/agent/subagent_lifecycle.py#L487-L523","documentation":"Validation error from SubagentLifecycleManager._validate_request(): the role field of SubagentLaunchRequest must be exactly 'leaf' or 'orchestrator'. Any other value (including None, '', 'worker', 'sub-agent', or differently-cased strings) is rejected.","triggerScenarios":"Calling launch() with role=\"worker\", role=\"root\", role=None (if the dataclass default is not one of the two), or role=\"LEAF\" (case-sensitive set membership check).","commonSituations":"Porting code from another framework whose role vocabulary differs; typos and casing mistakes; UI dropdowns offering role names that do not match the contract.","solutions":["Use exactly 'leaf' (focused worker, default) or 'orchestrator' (can spawn its own children) — lower-case, no variants.","Normalize user-supplied role strings to the two allowed values at your boundary, mapping unknowns to 'leaf'.","Remember orchestrator is additionally gated by delegation.orchestrator_enabled and delegation.max_spawn_depth in config.yaml."],"exampleFix":"# before\nrequest = SubagentLaunchRequest(goal=g, role=\"worker\")\n\n# after\nrole = \"orchestrator\" if user_role == \"orchestrator\" else \"leaf\"\nrequest = SubagentLaunchRequest(goal=g, role=role)","handlingStrategy":"type-guard","validationCode":"ALLOWED_ROLES = {\"leaf\", \"orchestrator\"}\nrole = role if role in ALLOWED_ROLES else \"leaf\"\nrequest = SubagentLaunchRequest(goal=goal, role=role)","typeGuard":"def is_valid_role(value: object) -> bool:\n    return value in (\"leaf\", \"orchestrator\")","tryCatchPattern":null,"preventionTips":["Use only the literal strings 'leaf' and 'orchestrator' (case-sensitive).","Normalize external role vocabularies to these two values at your boundary.","Default to 'leaf'; orchestrator is gated by delegation config anyway."],"tags":["subagents","delegation","validation","role"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}