{"record":{"id":"60324a4674e2a38b","repo":"chenhg5/cc-connect","slug":"write-hook-response-w","errorCode":null,"errorMessage":"write hook response: %w","messagePattern":"write hook response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"agent/antigravityhook/protocol.go","lineNumber":72,"sourceCode":"\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 {\n\t\treturn fmt.Errorf(\"send permission request: %w\", err)\n\t}\n\n\tvar response BridgeResponse\n\tif err := json.NewDecoder(io.LimitReader(conn, 64<<10)).Decode(&response); err != nil {\n\t\treturn fmt.Errorf(\"read permission response: %w\", err)\n\t}\n\tswitch response.Decision {\n\tcase \"allow\", \"deny\":\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid permission decision %q\", response.Decision)\n\t}\n\n\tif err := json.NewEncoder(out).Encode(response); err != nil {\n\t\treturn fmt.Errorf(\"write hook response: %w\", err)\n\t}\n\treturn nil\n}\n","sourceCodeStart":54,"sourceCodeEnd":76,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/antigravityhook/protocol.go#L54-L76","documentation":"After a valid decision is obtained, Relay re-encodes the BridgeResponse as JSON to the hook's stdout writer (out), which Antigravity reads. This error wraps a failure writing/encoding that final response — the stdout pipe is closed, broken, or the write fails at the OS level.","triggerScenarios":"Relay() calls json.NewEncoder(out).Encode(response) where out is the hook process's stdout; encoding fails if the parent Antigravity process already exited or closed the pipe (EPIPE), stdout is redirected to a full disk, or out is a writer that rejects the write.","commonSituations":"The IDE/agent that spawned the permission hook was closed by the user while a decision was pending, so the pipe is broken when the human finally answers in chat; a wrapper script closed stdout prematurely; disk-full on the machine running the hook.","solutions":["Re-run the agent operation — this is usually a lost race where the parent process exited while the decision was pending","Avoid closing/killing the Antigravity process while a permission prompt is outstanding in the messaging app","Check disk space and stdout redirection targets on the machine where the hook runs","If wrapping the hook in a script, keep the original stdout fd open and pass it through unchanged"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := Relay(in, out, addr, token); err != nil {\n    if errors.Is(err, syscall.EPIPE) || strings.Contains(err.Error(), \"write hook response\") {\n        log.Warn(\"parent process gone before decision could be delivered\", \"err\", err)\n        return nil\n    }\n    return err\n}","preventionTips":["Don't kill or close the agent/IDE process while a permission decision is pending","Keep the hook's stdout fd unredirected or faithfully passed through by wrapper scripts","Monitor disk space on hosts running hooks","Document that answering a pending chat prompt after the parent exited produces this benign error"],"tags":["io","broken-pipe","ipc"],"backgroundTag":"broken-pipe","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"}