{"record":{"id":"7b21b6ccb1fa4a4c","repo":"chenhg5/cc-connect","slug":"read-permission-response-w","errorCode":null,"errorMessage":"read permission response: %w","messagePattern":"read permission response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/antigravityhook/protocol.go","lineNumber":63,"sourceCode":"\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 {\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":45,"sourceCodeEnd":76,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/antigravityhook/protocol.go#L45-L76","documentation":"Relay in agent/antigravityhook/protocol.go sends a permission-hook request to the cc-connect bridge over a TCP connection and decodes the JSON BridgeResponse. This error wraps any failure while reading/decoding the response from the bridge socket — the connection closed early, the peer sent non-JSON bytes, the payload exceeded the 64 KiB cap, or a network I/O error occurred. It exists so the hook fails closed with context instead of silently treating a broken bridge as an allow.","triggerScenarios":"Relay() calls json.NewDecoder(io.LimitReader(conn, 64<<10)).Decode(&response) after dialing the bridge address; the decode fails when the bridge process exited before replying, the socket closed mid-write, a non-JSON payload arrives on the CC_CONNECT_AGY_PERMISSION_ADDR socket, or the response exceeds 64 KiB.","commonSituations":"The cc-connect session owning the bridge crashed or was restarted while an Antigravity permission hook was pending; a stale hook fired against an old/dead bridge port; another service is listening on the address and returns a non-JSON HTTP response.","solutions":["Restart the cc-connect session that owns the permission bridge, then re-run the agent operation that triggered the hook","Verify CC_CONNECT_AGY_PERMISSION_ADDR points to the live bridge socket and that no other process has claimed that port","Check cc-connect logs for a bridge listener crash (e.g. panics in the permission handler) and fix the underlying crash","Re-run the hook manually to see if the failure is transient (bridge was momentarily unavailable)"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if addr := os.Getenv(\"CC_CONNECT_AGY_PERMISSION_ADDR\"); addr == \"\" { t.Fatal(\"bridge address env not set\") }\nc, err := net.DialTimeout(\"tcp\", os.Getenv(\"CC_CONNECT_AGY_PERMISSION_ADDR\"), 5*time.Second)\nif err != nil { log.Fatal(\"bridge not reachable: \", err) }","typeGuard":"func hasLiveBridge(addr string) bool { c, err := net.DialTimeout(\"tcp\", addr, 5*time.Second); if err != nil { return false }; _ = c.Close(); return true }","tryCatchPattern":"decision, err := antigravityhook.Relay(in, out, addr, token)\nif err != nil {\n    var netErr net.Error\n    if errors.As(err, &netErr) { /* retry dial or fail closed */ }\n    return fmt.Errorf(\"permission relay: %w\", err)\n}","preventionTips":["Keep the cc-connect bridge session alive while agent permission hooks are pending","Monitor bridge listener health and log dial/read failures on the server side","Keep bridge responses well under the 64 KiB limit","Treat relay errors as deny (fail closed) and alert instead of retrying indefinitely"],"tags":["json","ipc","network"],"backgroundTag":"json-decode-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}