{"record":{"id":"e58813d264932e66","repo":"chenhg5/cc-connect","slug":"antigravity-permission-request-q-is-already-reso","errorCode":null,"errorMessage":"antigravity: permission request %q is already resolved","messagePattern":"antigravity: permission request %q is already resolved","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"agent/antigravity/permission_bridge.go","lineNumber":324,"sourceCode":"\nfunc (b *agyPermissionBridge) RespondPermission(requestID string, result core.PermissionResult) error {\n\tbehavior := strings.ToLower(strings.TrimSpace(result.Behavior))\n\tif behavior != \"allow\" && behavior != \"deny\" {\n\t\treturn fmt.Errorf(\"antigravity: invalid permission behavior %q\", result.Behavior)\n\t}\n\tresult.Behavior = behavior\n\n\tb.pendingMu.Lock()\n\tch := b.pending[requestID]\n\tb.pendingMu.Unlock()\n\tif ch == nil {\n\t\treturn fmt.Errorf(\"antigravity: unknown permission request %q\", requestID)\n\t}\n\tselect {\n\tcase ch <- result:\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"antigravity: permission request %q is already resolved\", requestID)\n\t}\n}\n\nfunc (b *agyPermissionBridge) Close() {\n\tb.closeOnce.Do(func() {\n\t\tb.cancel()\n\t\t_ = b.listener.Close()\n\t\tb.wg.Wait()\n\t\t_ = os.RemoveAll(b.rootDir)\n\t})\n}\n","sourceCodeStart":306,"sourceCodeEnd":336,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/antigravity/permission_bridge.go#L306-L336","documentation":"RespondPermission delivers the result over a buffered (capacity-1) channel per pending request. If the channel is full, the request was already resolved by a previous response, so this error is returned instead of blocking or double-delivering. It is a duplicate-response guard.","triggerScenarios":"Calling RespondPermission twice with the same requestID in quick succession (double-click, retry after a slow response, both allow and deny buttons wired to the same handler).","commonSituations":"Impatient user tapping a permission button twice; platform retry logic re-posting the callback; two chat members both answering the same shared-session permission card.","solutions":["Treat this as benign — the first response already won; disable the buttons after the first click.","Track answered request IDs at the call site and skip duplicates before calling RespondPermission.","Debounce/deduplicate platform button callbacks (idempotency key = requestID).","No recovery is possible for the second call; the result must be considered lost."],"exampleFix":"// before\nbridge.RespondPermission(id, result)\nbridge.RespondPermission(id, result) // second call errors\n// after\nif answered[id] { return }; answered[id] = true\nbridge.RespondPermission(id, result)","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := bridge.RespondPermission(id, result); err != nil && strings.Contains(err.Error(), \"already resolved\") {\n    // benign duplicate; log at debug and no-op\n}","preventionTips":["Debounce platform button callbacks keyed by requestID.","Disable buttons after the first click (edit the card).","Keep a set of answered request IDs at the call site."],"tags":["go","permission","race-condition","antigravity"],"backgroundTag":"invalid-state-transition","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"}