github/copilot-sdk · error
invalid hook input
Error message
invalid hook input: %w
What it means
In handleHooksInvoke, when the CLI delivers a preToolUse hook callback, the raw JSON payload is unmarshalled into PreToolUseHookInput. If the JSON does not match the expected schema, the SDK returns this error wrapping the json.Unmarshal error instead of invoking the registered OnPreToolUse hook.
Solutions
- Upgrade the Go SDK and the Copilot CLI to matching versions so the PreToolUseHookInput schema lines up.
- Log the raw input payload (enable debug logging) and compare it to the PreToolUseHookInput struct fields.
- Check that your hooks registration (OnPreToolUse) is configured for the correct hook type string.
Defensive patterns
Strategy: try-catch
Try / catch
out, err := session.handleHooksInvoke("preToolUse", raw)
if err != nil && strings.HasPrefix(err.Error(), "invalid hook input:") {
// schema mismatch: log raw payload, check SDK/CLI versions
} Prevention
- Keep SDK and CLI versions matched
- Enable debug logging to capture raw hook payloads
- Pin CLI versions in deployments and upgrade SDK with them
When it happens
Trigger: A preToolUse hooksInvoke request whose req.Input JSON fails to decode into PreToolUseHookInput (wrong/missing fields, wrong types, malformed JSON).
Common situations: SDK and CLI versions disagree on the hook payload schema; CLI update adds/renames fields with different types; a custom/older CLI binary sending non-conformant input.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- failed to unmarshal response
- failed to unmarshal arguments into %T
- marshal elicitation schema property
- marshal elicitation schema wrapper for property
- decode elicitation schema property
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/64c9bd5d03798bba.
Report an issue: GitHub.
Appendix: source
Thrown at go/session.go:764
func (s *Session) handleHooksInvoke(hookType string, rawInput json.RawMessage) (any, error) {
hooks := s.getHooks()
if hooks == nil {
return nil, nil
}
invocation := HookInvocation{
SessionID: s.SessionID,
}
switch hookType {
case "preToolUse":
if hooks.OnPreToolUse == nil {
return nil, nil
}
var input PreToolUseHookInput
if err := json.Unmarshal(rawInput, &input); err != nil {
return nil, fmt.Errorf("invalid hook input: %w", err)
}
return hooks.OnPreToolUse(input, invocation)
case "preMcpToolCall":
if hooks.OnPreMCPToolCall == nil {
return nil, nil
}
var input PreMCPToolCallHookInput
if err := json.Unmarshal(rawInput, &input); err != nil {
return nil, fmt.Errorf("invalid hook input: %w", err)
}
return hooks.OnPreMCPToolCall(input, invocation)
case "postToolUse":
if hooks.OnPostToolUse == nil {
return nil, nil
}
var input PostToolUseHookInputView on GitHub (pinned to cd8cf15dc3)