oraios/serena · error · ValueError
Tool name is required in the hook input data
Error message
Tool name is required in the hook input data
What it means
ToolHook subclasses (e.g. pre/post-tool-use hooks) require the hook input to name the tool being triggered. __init__ reads tool_name/toolName, normalizes to lowercase, and raises ValueError if it is empty, because the hook cannot dispatch without knowing which tool fired.
Source
Thrown at src/serena/hooks.py:73
"read",
"diagnostics",
"memory",
"onboarding",
"config",
"list_file",
"find_file",
"shell",
"dashboard",
"restart_language_server",
)
)
def __init__(self, client: HookClient):
super().__init__(client)
_tool_name = self._input_data.get("tool_name") or self._input_data.get("toolName", "") or ""
_tool_name = str(_tool_name).lower().strip()
if not _tool_name:
raise ValueError("Tool name is required in the hook input data")
self._tool_name = _tool_name
raw_tool_input = self._input_data.get("tool_input") or self._input_data.get("toolInput")
# TODO: some agents, like copilot CLI, can send a string as value for raw_tool_input
# Example: "tool_input":"*** Begin Patch\n*** Add File: /Users/acbdef/.copilot/session-state/08a961db-02f0-4c7c-b783-1e9818290292/files/hook-tool-test-3.txt\n+third edit tool test\n*** End Patch\n"
# We currently don't parse such tool input and hence don't react to it in hooks
self._tool_input: dict | None = raw_tool_input if isinstance(raw_tool_input, dict) else None
# only relevant in claude code at the moment, (not all events include this field; default to empty string)
raw_permission_mode = self._input_data.get("permission_mode") or self._input_data.get("permissionMode") or ""
self._permission_mode = str(raw_permission_mode).strip()
@dataclass
class OutputData:
permission_decision: Literal["deny", "allow"]
permission_decision_reason: str
additional_context: str = ""
def to_json_string(self, client: HookClient) -> str:View on GitHub (pinned to 7fcbca7e62)
Solutions
- Include a non-empty "tool_name" in the hook input JSON
- Update the agent CLI/hook client so it forwards the tool name
- If testing hooks manually, replicate the full payload shape the agent sends
Example fix
// before
{"session_id": "abc", "tool_input": {"path": "x.py"}}
// after
{"session_id": "abc", "tool_name": "read_file", "tool_input": {"path": "x.py"}} Defensive patterns
Strategy: validation
Validate before calling
def validate_tool_hook(data: dict) -> str:
name = str(data.get("tool_name") or data.get("toolName") or "").lower().strip()
if not name:
raise ValueError("hook input JSON must include a non-empty tool_name")
return name Try / catch
try:
hook = ToolHook(client)
except ValueError as e:
if "Tool name" in str(e):
logging.error("Hook payload missing tool_name: check hook client schema")
else:
raise Prevention
- Always send tool_name (and tool_input as a dict) in tool hook payloads
- Keep the agent CLI and serena versions aligned
- Add a unit test asserting the hook payload contains tool_name
- Normalize field names (toolName vs tool_name) in custom clients
When it happens
Trigger: A hook event payload for a tool-based hook lacks tool_name/toolName or supplies an empty/whitespace string; custom hook clients that only forward tool_input.
Common situations: Custom agent integrations with incomplete hook payloads; schema drift between agent versions (toolName vs tool_name); hand-testing hook scripts with minimal JSON.
Understand the failure class
Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.
Related errors
- Session ID is required in the hook input data
- Cannot use both fixed_tools and excluded_tools/included_opti
- Unknown language backend '{backend_str}': valid values are {
- Invalid line_ending: {value!r}. Valid values are: {valid}
- Invalid language server: '{orig_language_str}'.\nValid value
AI-assisted analysis of oraios/serena@7fcbca7e62 (2026-08-29).
Data as JSON: /api/errors/cba316432501e8da.
Report an issue: GitHub.