Send raw error to analytics for chat agent failures#5984
Conversation
Previously only the sanitized user-friendly message was sent to PostHog, making it impossible to diagnose failures remotely. Now sends the raw BridgeError alongside so we can see the actual cause (API key errors, connection issues, etc.) in analytics. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR improves observability for chat agent failures by forwarding the raw Key concern:
Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant Bridge as ACPBridge (Node)
participant CP as ChatProvider
participant AM as AnalyticsManager
participant PH as PostHog
participant MX as Mixpanel
Bridge->>CP: throw BridgeError.agentError(rawMsg)
CP->>CP: error.localizedDescription → sanitized user string
CP->>CP: String(describing: bridgeError) → raw enum string
Note over CP: ⚠️ rawMsg may contain sensitive data
CP->>AM: chatAgentError(error: sanitized, rawError: raw)
AM->>PH: track("chat_agent_error", {error, raw_error})
AM->>MX: track("Chat Agent Error", {error, raw_error})
Note over PH,MX: raw_error bypasses BridgeError.errorDescription sanitization
Reviews (1): Last reviewed commit: "fix(desktop): send raw error to analytic..." | Re-trigger Greptile |
| if let bridgeError = error as? BridgeError { | ||
| rawError = String(describing: bridgeError) | ||
| } else { | ||
| rawError = "\(error)" | ||
| } |
There was a problem hiding this comment.
Raw error bypasses security sanitization before reaching analytics
String(describing: bridgeError) for BridgeError.agentError produces the raw enum representation including its full associated string value. This gets forwarded to PostHog and Mixpanel, but the BridgeError.errorDescription implementation was specifically written to redact auth/key-related content (checking for "api key", "api_key", "leaked", "unauthorized", "forbidden", etc.) before ever exposing the message. That sanitization is now bypassed for analytics.
If the node bridge surfaces an error from the upstream AI provider that embeds a credential value in its message text, the raw string would be sent to third-party analytics in full. The 500-char truncation is not a reliable mitigation because sensitive content typically appears at the beginning of such messages.
A safer approach is to apply the same redaction before sending to analytics:
case .agentError(let msg):
let lower = msg.lowercased()
let sensitiveKeywords = ["api key", "api_key", "leaked", "unauthorized",
"permission denied", "invalid key", "forbidden"]
let isAuthError = sensitiveKeywords.contains(where: lower.contains)
rawError = isAuthError
? "agentError([redacted auth/key error])"
: "agentError(\(String(msg.prefix(200))))"## Summary
Previously `chat_agent_error` PostHog events only contained the
sanitized user-friendly message (e.g., "AI service is temporarily
unavailable"), making it impossible to diagnose failures remotely. Now
sends the raw `BridgeError` alongside (e.g., `agentError("Internal
error: Invalid API key")`) so we can see the actual cause in analytics.
This was discovered investigating Miles Feldstein's failed onboarding —
we could see the error happened but couldn't determine the root cause
because the raw error was stripped.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Summary
Previously
chat_agent_errorPostHog events only contained the sanitized user-friendly message (e.g., "AI service is temporarily unavailable"), making it impossible to diagnose failures remotely. Now sends the rawBridgeErroralongside (e.g.,agentError("Internal error: Invalid API key")) so we can see the actual cause in analytics.This was discovered investigating Miles Feldstein's failed onboarding — we could see the error happened but couldn't determine the root cause because the raw error was stripped.
🤖 Generated with Claude Code