chenhg5/cc-connect · error
hook input is not valid JSON
Error message
hook input is not valid JSON
What it means
Relay validates that the hook's stdin payload is well-formed JSON using json.Valid and returns 'hook input is not valid JSON' otherwise. The payload is forwarded verbatim to the bridge, so it must be valid JSON before it is sent.
Source
Thrown at agent/antigravityhook/protocol.go:45
Decision string `json:"decision"`
Reason string `json:"reason,omitempty"`
}
// Relay forwards one Agy hook invocation to the owning cc-connect session.
func Relay(in io.Reader, out io.Writer, address, token string) error {
if strings.TrimSpace(address) == "" || strings.TrimSpace(token) == "" {
return fmt.Errorf("permission bridge environment is missing")
}
input, err := io.ReadAll(io.LimitReader(in, maxHookInput+1))
if err != nil {
return fmt.Errorf("read hook input: %w", err)
}
if len(input) > maxHookInput {
return fmt.Errorf("hook input exceeds %d bytes", maxHookInput)
}
if !json.Valid(input) {
return fmt.Errorf("hook input is not valid JSON")
}
conn, err := net.DialTimeout("tcp", address, bridgeDialTimeout)
if err != nil {
return fmt.Errorf("connect permission bridge: %w", err)
}
defer func() { _ = conn.Close() }()
// The listener is started before agy runs this hook, so dial failures should
// fail closed quickly. After connect, wait much longer for a human response.
_ = conn.SetDeadline(time.Now().Add(bridgeResponseTimeout))
if err := json.NewEncoder(conn).Encode(BridgeRequest{Token: token, HookInput: input}); err != nil {
return fmt.Errorf("send permission request: %w", err)
}
var response BridgeResponse
if err := json.NewDecoder(io.LimitReader(conn, 64<<10)).Decode(&response); err != nil {
return fmt.Errorf("read permission response: %w", err)View on GitHub (pinned to 4000b2338a)
Solutions
- Dump the exact stdin bytes (`tee /tmp/hookin.json`) to inspect what agy sent
- Test with a known-good minimal payload: `echo '{"session_id":"x"}' | hook`
- Ensure wrapper scripts don't alter or truncate stdin
- Check whether the payload was cut off at maxHookInput, producing truncated JSON
Example fix
// before (manual test)
$ agy-permission-hook
// after
$ echo '{"tool":"bash","command":"ls"}' | agy-permission-hook Defensive patterns
Strategy: validation
Validate before calling
raw, _ := io.ReadAll(os.Stdin)
if !json.Valid(raw) {
os.Stderr.WriteString("hook stdin must be valid JSON from agy\n")
os.Exit(2)
} Try / catch
if err := Relay(...); err != nil && strings.Contains(err.Error(), "not valid JSON") {
fmt.Fprintln(os.Stderr, "invalid hook input; verify agy invocation")
os.Exit(2)
} Prevention
- Never pipe hand-typed text into the hook; always valid JSON
- Check for truncation if inputs approach the size cap
- Keep hook wrapper scripts pass-through (no stdin rewriting)
When it happens
Trigger: The bytes read from stdin fail json.Valid — e.g. empty input, truncated payload, binary data, or manually piping non-JSON into the hook.
Common situations: Debugging the hook by running it manually without piping valid JSON; agy producing truncated output (possibly overlapping with the size cap); corrupted stdin wiring in custom wrappers.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- decode response: %w
- invalid JSON:
- invalid JSON:
- app_id/app_secret are required
- invalid remote image URL
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/d1f5567efcea411a.
Report an issue: GitHub.