fix(jsonrpc): keep scoped 401s from expiring session#2292
Conversation
📝 WalkthroughWalkthroughJSON-RPC session auto-cleanup now publishes ChangesSession-Expiry Classification and Dispatch
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/core/jsonrpc.rs (1)
184-188: ⚡ Quick winUse debug-level structured logs for diagnostics-only auth classification.
Line 184 and Line 199 are diagnostics branches; emitting them at
warncan create avoidable noise. Preferdebug/tracewith structured fields.Proposed adjustment
- log::warn!( - "[jsonrpc] confirmed session expiry for method '{}' — publishing SessionExpired: {}", - method, - sanitized_reason - ); + log::debug!( + method = %method, + reason = %sanitized_reason, + "[jsonrpc] confirmed session expiry — publishing SessionExpired" + ); ... - log::warn!( - "[jsonrpc] unauthorized error for method '{}' did not match OpenHuman session expiry — leaving session intact: {}", - method, - sanitized_reason - ); + log::debug!( + method = %method, + reason = %sanitized_reason, + "[jsonrpc] unauthorized error did not match OpenHuman session expiry — leaving session intact" + );As per coding guidelines:
src/**/*.rs: Uselogortracingcrate atdebugortracelevel for Rust diagnostic logs.Also applies to: 199-203
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/core/jsonrpc.rs` around lines 184 - 188, Replace the two diagnostic log::warn! calls (the "confirmed session expiry" branch that logs method and sanitized_reason and the subsequent diagnostic branch around lines 199–203) with debug- or trace-level logs and emit structured fields rather than interpolated text; specifically change those log::warn! invocations to log::debug!/log::trace! and include method and sanitized_reason as named fields (e.g., method=..., reason=...) so diagnostics are only visible at debug/trace level and are machine-parsable.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/core/jsonrpc.rs`:
- Around line 184-188: Replace the two diagnostic log::warn! calls (the
"confirmed session expiry" branch that logs method and sanitized_reason and the
subsequent diagnostic branch around lines 199–203) with debug- or trace-level
logs and emit structured fields rather than interpolated text; specifically
change those log::warn! invocations to log::debug!/log::trace! and include
method and sanitized_reason as named fields (e.g., method=..., reason=...) so
diagnostics are only visible at debug/trace level and are machine-parsable.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 4179fdf4-04a9-41c4-b1d7-1308e4cc509f
📒 Files selected for processing (3)
src/core/jsonrpc.rssrc/core/jsonrpc_tests.rssrc/core/observability.rs
graycyrus
left a comment
There was a problem hiding this comment.
Clean — moving to approval queue.
Well-targeted fix. The core change — delegating is_session_expired_error to the strict observability::is_session_expired_message classifier — is the right call. Generic downstream 401s (BYO-key, Composio, channel providers) no longer nuke the app session, while all four canonical OpenHuman session-expired wire shapes still trigger cleanup as before.
Good details:
is_unconfirmed_unauthorized_errorkeeps diagnostic visibility for scoped 401s without feeding theSessionExpiredpublish path.sanitize_api_erroris called once before branching — no duplication, no PII in logs.- Tests cover the full classification matrix: true session expiry, generic 401, invalid token, and the OpenHuman API error body shape.
- All CI green, coverage gate passes.
Re issue alignment: #2286 acceptance criteria are met. The follow-up to identify the exact Discord card-click RPC (#2285) is correctly scoped as separate work — this PR eliminates the root cause regardless of which specific RPC triggers the downstream 401.
|
nice one @aqilaziz, love how this narrows the session-expiry check to actual openhuman shapes so random downstream 401s stop nuking sessions 🙌 the sanitized diagnostic logging is a really thoughtful touch too. thanks for keeping pushing on this stuff 🔥 |
Summary
401 Unauthorizedandinvalid tokenerrors from publishingSessionExpired.Problem
401+unauthorizedtext as a global app session expiry.Solution
observability::is_session_expired_messageclassifier at the JSON-RPC dispatch boundary.SessionExpiredpublication for explicit OpenHuman auth states:session expired,SESSION_EXPIRED,no backend session token, andsession JWT required.observabilityto match the stricter dispatch behavior.Submission Checklist
## Related— N/A: no matrix feature ID changed.docs/RELEASE-MANUAL-SMOKE.md) — N/A: no release smoke checklist surface changed.Closes #NNNin the## RelatedsectionImpact
Related
AI Authored PR Metadata (required for Codex/Linear PRs)
Linear Issue
Commit & Branch
codex/2286-session-expired-narrowing6f98f1e28a113afd0ea47908d0a397ecfe681560Validation Run
pnpm --filter openhuman-app format:check— N/A: no frontend changes.pnpm typecheck— N/A: no TypeScript changes.cargo fmt --checkpassed.Validation Blocked
command:cargo test --lib is_session_expired_error --manifest-path Cargo.tomlerror:whisper-rs-sysbuild script could not findclang.dll/libclang.dll;LIBCLANG_PATHis unset in this Windows environment.impact:focused Rust tests could not run locally, but the changed classifier tests are included for CI.Behavior Changes
401 Unauthorizedtext no longer publishesDomainEvent::SessionExpired.Parity Contract
SESSION_EXPIRED, missing backend session token, and missing session JWT still clear the app session.Duplicate / Superseded PR Handling