Skip to content

fix(composio): empty connections in direct mode without api key (TAURI-RUST-R4)#3198

Merged
graycyrus merged 2 commits into
tinyhumansai:mainfrom
oxoxDev:fix/tauri-rust-r4-composio-listconns-empty-on-no-key
Jun 2, 2026
Merged

fix(composio): empty connections in direct mode without api key (TAURI-RUST-R4)#3198
graycyrus merged 2 commits into
tinyhumansai:mainfrom
oxoxDev:fix/tauri-rust-r4-composio-listconns-empty-on-no-key

Conversation

@oxoxDev
Copy link
Copy Markdown
Contributor

@oxoxDev oxoxDev commented Jun 2, 2026

Summary

  • composio_list_connections now returns an empty list (not an error) when the user has selected Composio direct mode but not yet configured an API key — a valid setup state, not a failure.
  • Stops the desktop UI's 5 s connection poll from funnelling the factory's "no api key is configured" error to Sentry on every tick (TAURI-RUST-R4: ~3.2k events, single user, release 0.57.5).
  • Key-presence detection mirrors the mode-aware factory's own keychain-or-config.toml resolution, so a key supplied via config.toml is never wrongly treated as absent.
  • Defense-in-depth: expected_error_kind now classifies "no api key is configured" as ApiKeyMissing for the direct-mode ops a user invokes explicitly (execute/authorize).

Problem

When a user toggles Composio to direct mode but hasn't pasted their API key yet, the mode-aware factory (composio/client.rs) bails with composio direct mode selected but no api key is configured. The desktop UI polls composio_list_connections every 5 s, so this error was constructed on every tick and propagated through the central RPC dispatcher (core/jsonrpc.rs) into Sentry — until the user finally entered a key. The result was a single user generating thousands of error events for an expected, user-controlled configuration state with no actionable signal.

The background sync tick (memory_sync/composio/periodic.rs) already handled this gracefully (skip). The UI-poll path never got the symmetric treatment.

Solution

  • Add direct_mode_without_key(config) in composio/ops.rs: true only when config.composio.mode == "direct" and no key resolves from either the keychain (credentials::get_composio_api_key) or config.composio.api_key. This deliberately mirrors the factory's own resolution to avoid hiding a config.toml-supplied key.
  • composio_list_connections short-circuits to Ok(ComposioConnectionsResponse { connections: vec![] }) before the factory call and before sync_cache_with_connections, so no error is constructed and the integrations cache is left untouched.
  • This is a fix to the root cause (mis-modelling a valid setup state as an operation failure), not suppression — the error simply no longer occurs. Genuine failures still error and reach Sentry: backend no-session, keychain read failure, and an actually-invalid key (the v3 HTTP 401: Invalid API key path, classified separately).
  • The Settings → Composio panel continues to drive the "enter your key" prompt off the separate api_key_set status, so the user is still told exactly what to do — nothing is hidden.
  • expected_error_kind gains a "no api key is configured" substring under the existing ApiKeyMissing arm, demoting any residual explicit-invoke emit to warn! (logged, not Sentry). A guard test pins that a genuine invalid_api_key 401 stays actionable.

Submission Checklist

If a section does not apply to this change, mark the item as N/A with a one-line reason. Do not delete items.

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy
  • Diff coverage ≥ 80% — every changed product line is exercised: the guard helper (4 cases incl. backend-mode / config-key / keychain-key), the empty-list path (composio_list_connections_returns_empty_when_direct_mode_no_key), and the classifier arm (+ over-suppression guard).
  • N/A: behaviour-only fix to an existing feature — no added/removed/renamed coverage-matrix feature row.
  • N/A: no coverage-matrix feature IDs affected by this change.
  • No new external network dependencies introduced (mock backend used per Testing Strategy)
  • N/A: does not touch release-cut smoke surfaces (internal RPC error-handling only).
  • N/A: Sentry-only issue, no GitHub issue to close — Sentry-Issue: TAURI-RUST-R4 (see Related).

Impact

  • Desktop (CLI/core): direct-mode users without a key see an empty connection list instead of a silent error churn; UX is unchanged (the not-connected state is already driven by api_key_set).
  • Observability: removes the dominant 5 s-poll Sentry leak at its source; residual explicit-invoke emits are demoted, not dropped (still in logs).
  • No migration, no schema change, no new dependency. No security implication — genuine auth failures (invalid key, no session) still surface.

Related

  • Closes: N/A — Sentry-only
  • Sentry-Issue: TAURI-RUST-R4
  • Follow-up PR(s)/TODOs: none

AI Authored PR Metadata (required for Codex/Linear PRs)

Keep this section for AI-authored PRs. For human-only PRs, mark each field N/A.

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: fix/tauri-rust-r4-composio-listconns-empty-on-no-key
  • Commit SHA: 50e1170e, d16fd54f

Validation Run

  • N/A: pnpm --filter openhuman-app format:check — no frontend (app/) changes.
  • N/A: pnpm typecheck — no frontend changes.
  • Focused tests: cargo test --lib openhuman::composio::ops (74 passed), cargo test --lib core::observability (135 passed)
  • Rust fmt/check (if changed): cargo fmt --check clean; cargo check --workspace clean; cargo clippy --lib no new findings
  • N/A: Tauri fmt/check — no app/src-tauri changes.

Validation Blocked

  • command: N/A
  • error: N/A
  • impact: N/A

Behavior Changes

  • Intended behavior change: composio_list_connections returns an empty list instead of erroring when direct mode is selected with no API key configured.
  • User-visible effect: none beyond the existing not-connected state; the error no longer churns to Sentry.

Parity Contract

  • Legacy behavior preserved: backend mode unchanged; genuine failures (no session, keychain error, invalid key) still error; a config.toml-supplied key is honoured (guard helper mirrors the factory's keychain-or-config resolution).
  • Guard/fallback/dispatch parity checks: empty short-circuit runs before the factory and cache sync; direct_mode_without_key returns false for backend mode and for any present key.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): none (dedup ran against open + 30-day-merged upstream PRs)
  • Canonical PR: this
  • Resolution (closed/superseded/updated): N/A

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of missing API key configuration in Direct mode—now gracefully returns an empty list instead of failing.
    • Enhanced error classification for API key-related issues, recognizing multiple error message variations.

oxoxDev added 2 commits June 2, 2026 14:26
…y (TAURI-RUST-R4)

Direct mode selected with no API key configured is a valid, user-controlled
setup state, not an operation failure. The desktop UI polls list_connections
every 5s; without a key the mode-aware factory bailed on every tick and the
error funnelled to Sentry until the user pasted a key (~3.2k events, single
user). Mirror periodic.rs's graceful skip: short-circuit to a truthful empty
list (no key -> no tenant -> no connections) before the factory and cache
sync. Key presence mirrors the factory's own keychain-or-config.toml check so
a config.toml key is never wrongly treated as absent.
…ing (TAURI-RUST-R4)

Defense-in-depth for direct-mode composio ops the user invokes explicitly
(execute/authorize) that can still surface the factory's no-key bail. Same
user-config state with no Sentry-actionable signal; demote to ApiKeyMissing
(warn!, still logged). Guard test pins that a genuine invalid_api_key 401
stays actionable (None -> Sentry).
@oxoxDev oxoxDev requested a review from a team June 2, 2026 08:58
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cb8f6433-c48f-4cb9-9e5d-c8f565d39f5f

📥 Commits

Reviewing files that changed from the base of the PR and between 1e03dd2 and d16fd54.

📒 Files selected for processing (3)
  • src/core/observability.rs
  • src/openhuman/composio/ops.rs
  • src/openhuman/composio/ops_tests.rs

📝 Walkthrough

Walkthrough

The PR hardens Composio Direct mode handling by recognizing additional "API key not configured" message patterns in error classification, then adding an early-return guard in composio_list_connections to return empty results instead of failing when no key is set.

Changes

Composio Direct Mode Missing Key Guard

Layer / File(s) Summary
Error Classification Expansion for API Key Missing
src/core/observability.rs
expected_error_kind recognizes additional message variants ("no API key is configured", "API key not set", "missing API key") and routes them to ApiKeyMissing. Tests verify the new Composio direct-mode message classification and guard against misclassifying OpenAI's invalid_api_key 401.
Direct Mode No-Key Detection and Early Return
src/openhuman/composio/ops.rs, src/openhuman/composio/ops_tests.rs
direct_mode_without_key predicate detects Direct mode without configured key. composio_list_connections short-circuits this state to return empty connections before calling create_composio_client. Tests verify the predicate across backend/Direct mode configurations and confirm the async early-return behavior with empty-list logging.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • tinyhumansai/openhuman#2830: Expands ApiKeyMissing message-shape detection in expected_error_kind with additional API key variants and corresponding unit tests.
  • tinyhumansai/openhuman#2915: Improves ApiKeyMissing detection logic to classify "*_api_key is not configured" messages while avoiding false positives.
  • tinyhumansai/openhuman#2544: Adds session-expiry and provider-auth classification regression tests to prevent Composio/OpenAI key errors from being misclassified.

Suggested labels

rust-core, bug, sentry-traced-bug

Suggested reviewers

  • graycyrus
  • sanil-23

Poem

🐰 A rabbit hops through Direct mode's door,
But found no key upon the floor.
Now gracefully returns with empty cheer,
And whispers "no API key here!"
No crashes now—just silent, clear.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: returning empty connections in direct mode when no API key is configured, rather than throwing an error.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. sentry-traced-bug Bug identified via Sentry triage bug labels Jun 2, 2026
@oxoxDev oxoxDev requested a review from graycyrus June 2, 2026 09:20
graycyrus
graycyrus previously approved these changes Jun 2, 2026
Copy link
Copy Markdown
Contributor

@graycyrus graycyrus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean fix. The root cause is correctly identified — the 5 s poll was treating a valid setup state as an operation failure, and the fix addresses that at the source rather than suppressing symptoms.

A few things I verified:

  • direct_mode_without_key mirrors the factory's own key resolution (keychain-or-config.toml) correctly. The config.toml fallback test catches the subtle case where a user configured their key outside the keychain — good edge case coverage.
  • The error propagation from get_composio_api_key is right: if the keychain is locked or errors, we propagate rather than silently returning empty, which is the correct semantic (genuine keychain failure != "no key configured").
  • The expected_error_kind classifier addition is defense-in-depth for explicit execute/authorize invocations — those can still surface the error, and classifying it as ApiKeyMissing keeps Sentry clean without dropping the signal. The over-suppression guard test (invalid 401 stays None) is exactly what I'd want to see.
  • Short-circuiting before create_composio_client and sync_cache_with_connections means no error object is constructed and the integrations cache is left untouched — correct ordering.
  • Backend mode is fully unaffected (guard returns false immediately). Confirmed by test.

Coverage is solid: 4 unit cases on the helper (backend mode, no-key, config.toml key, keychain key) plus the async integration test on composio_list_connections itself. The periodic.rs parity is now explicit and symmetric.

Approved.

@graycyrus graycyrus dismissed their stale review June 2, 2026 14:17

Dismissing approval — this repo's review automation does not auto-approve. Re-posting the same analysis as a comment; final approval is done manually by a maintainer.

@graycyrus graycyrus merged commit e60bccb into tinyhumansai:main Jun 2, 2026
25 of 31 checks passed
graycyrus

This comment was marked as outdated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. sentry-traced-bug Bug identified via Sentry triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants