chenhg5/cc-connect · error
invalid permission decision %q
Error message
invalid permission decision %q
What it means
After decoding a BridgeResponse, Relay validates that the decision field is exactly "allow" or "deny". This error is thrown when the bridge returned a decision value outside that enum (including an empty string when a malformed/truncated JSON object decoded with zeroed fields). It protects the hook protocol so only unambiguous decisions are forwarded to Antigravity.
Source
Thrown at agent/antigravityhook/protocol.go:68
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 {
return fmt.Errorf("send permission request: %w", err)
}
var response BridgeResponse
if err := json.NewDecoder(io.LimitReader(conn, 64<<10)).Decode(&response); err != nil {
return fmt.Errorf("read permission response: %w", err)
}
switch response.Decision {
case "allow", "deny":
default:
return fmt.Errorf("invalid permission decision %q", response.Decision)
}
if err := json.NewEncoder(out).Encode(response); err != nil {
return fmt.Errorf("write hook response: %w", err)
}
return nil
}
View on GitHub (pinned to 4000b2338a)
Solutions
- Upgrade the antigravityhook binary and cc-connect to matching versions so the bridge response schema is aligned
- Inspect what the bridge actually returned (log the raw response before validation) to identify the unexpected decision value
- Check whether the bridge hit an internal error and replied with a non-decision payload; fix that error first
- Ensure no unrelated service is bound to the CC_CONNECT_AGY_PERMISSION_ADDR port echoing foreign JSON
Defensive patterns
Strategy: validation
Validate before calling
var resp BridgeResponse
if err := json.Unmarshal(raw, &resp); err != nil { return err }
if resp.Decision != "allow" && resp.Decision != "deny" { return fmt.Errorf("bad decision %q", resp.Decision) } Type guard
func validDecision(d string) bool { return d == "allow" || d == "deny" } Try / catch
if err := Relay(in, out, addr, token); err != nil {
if strings.Contains(err.Error(), "invalid permission decision") {
log.Error("bridge returned malformed decision — check version compatibility", "err", err)
}
return err
} Prevention
- Keep hook binary and cc-connect versions in lockstep
- On the bridge side, always emit {"decision":"allow"|"deny"} even on internal errors
- Reject non-decision payloads early in bridge code with clear server logs
- Pin/verify no other service binds the bridge port
When it happens
Trigger: The bridge peer on CC_CONNECT_AGY_PERMISSION_ADDR sends a JSON object whose "decision" is not "allow" or "deny" — e.g. an error payload like {"error":"..."}, an empty JSON object {} (decision decodes to ""), or a bridge implementation using different decision vocabulary.
Common situations: Version mismatch between the hook binary and the cc-connect bridge (bridge protocol changed); the bridge answered with an error object instead of a decision; a third-party service occupying the port returns its own JSON shape.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- codex app-server initialize: %w
- app_id/app_secret are required
- invalid remote image URL
- antigravity: invalid permission behavior %q
- hook input is not valid JSON
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/4ac93f8f4d1c3839.
Report an issue: GitHub.