{"record":{"id":"7fb189147749c029","repo":"chenhg5/cc-connect","slug":"read-hook-input-w","errorCode":null,"errorMessage":"read hook input: %w","messagePattern":"read hook input: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/antigravityhook/protocol.go","lineNumber":39,"sourceCode":"type BridgeRequest struct {\n\tToken     string          `json:\"token\"`\n\tHookInput json.RawMessage `json:\"hook_input\"`\n}\n\ntype BridgeResponse struct {\n\tDecision string `json:\"decision\"`\n\tReason   string `json:\"reason,omitempty\"`\n}\n\n// Relay forwards one Agy hook invocation to the owning cc-connect session.\nfunc Relay(in io.Reader, out io.Writer, address, token string) error {\n\tif strings.TrimSpace(address) == \"\" || strings.TrimSpace(token) == \"\" {\n\t\treturn fmt.Errorf(\"permission bridge environment is missing\")\n\t}\n\n\tinput, err := io.ReadAll(io.LimitReader(in, maxHookInput+1))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read hook input: %w\", err)\n\t}\n\tif len(input) > maxHookInput {\n\t\treturn fmt.Errorf(\"hook input exceeds %d bytes\", maxHookInput)\n\t}\n\tif !json.Valid(input) {\n\t\treturn fmt.Errorf(\"hook input is not valid JSON\")\n\t}\n\n\tconn, err := net.DialTimeout(\"tcp\", address, bridgeDialTimeout)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"connect permission bridge: %w\", err)\n\t}\n\tdefer func() { _ = conn.Close() }()\n\t// The listener is started before agy runs this hook, so dial failures should\n\t// fail closed quickly. After connect, wait much longer for a human response.\n\t_ = conn.SetDeadline(time.Now().Add(bridgeResponseTimeout))\n\n\tif err := json.NewEncoder(conn).Encode(BridgeRequest{Token: token, HookInput: input}); err != nil {","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/antigravityhook/protocol.go#L21-L57","documentation":"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).","triggerScenarios":"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.","commonSituations":"agy killed mid-hook invocation; hook stdin mis-wired when run manually for debugging; container/pty environments that close stdin early.","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`"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := Relay(in, out, addr, tok); err != nil && strings.HasPrefix(err.Error(), \"read hook input:\") {\n    log.Printf(\"transient stdin read failure, retrying: %v\", err)\n}","preventionTips":["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"],"tags":["io","stdin","hook"],"backgroundTag":"file-read-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}