chenhg5/cc-connect · error
read hook input: %w
Error message
read hook input: %w
What it means
Relay wraps the underlying io.ReadAll failure when reading the hook's stdin payload: 'read hook input: %w'. Agy pipes the hook invocation JSON into the hook's stdin; if that read fails at the OS level the error is wrapped and returned, causing the hook to fail closed (deny).
Source
Thrown at agent/antigravityhook/protocol.go:39
type BridgeRequest struct {
Token string `json:"token"`
HookInput json.RawMessage `json:"hook_input"`
}
type BridgeResponse struct {
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 {View on GitHub (pinned to 4000b2338a)
Solutions
- Verify the hook is invoked by agy normally (stdin piped) rather than run interactively
- Retry the triggering action in agy — usually transient
- Inspect the wrapped %w error for the exact OS cause (e.g. 'file already closed')
- If testing, pass a real JSON payload via stdin: `echo '{}' | hook`
Defensive patterns
Strategy: retry
Try / catch
if err := Relay(in, out, addr, tok); err != nil && strings.HasPrefix(err.Error(), "read hook input:") {
log.Printf("transient stdin read failure, retrying: %v", err)
} Prevention
- Don't run the hook interactively; it expects agy to pipe stdin
- Keep agy healthy so it doesn't die mid-hook
- Test hooks with piped payloads, not a TTY
When it happens
Trigger: io.ReadAll(io.LimitReader(in, maxHookInput+1)) returns err != nil — stdin closed prematurely, broken pipe from the parent agy process, or I/O error on the underlying fd.
Common situations: agy killed mid-hook invocation; hook stdin mis-wired when run manually for debugging; container/pty environments that close stdin early.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- reading stdin: %w
- read stdin: %w
- read stdout: %w
- permission bridge environment is missing
- hook input exceeds %d bytes
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/7fb189147749c029.
Report an issue: GitHub.