Skip to content

fix(chat): show specific error messages instead of generic 'Something went wrong'#1566

Open
PranavAgarkar07 wants to merge 1 commit into
tinyhumansai:mainfrom
PranavAgarkar07:fix/chat-generic-error-1506
Open

fix(chat): show specific error messages instead of generic 'Something went wrong'#1566
PranavAgarkar07 wants to merge 1 commit into
tinyhumansai:mainfrom
PranavAgarkar07:fix/chat-generic-error-1506

Conversation

@PranavAgarkar07
Copy link
Copy Markdown

@PranavAgarkar07 PranavAgarkar07 commented May 12, 2026

Summary

When chat inference fails, users currently always see "Something went wrong. Please try again." with no indication of why. This fix classifies errors into actionable categories and shows a specific message for each.

Changes

Rust backend (src/openhuman/channels/providers/web.rs):

  • Added classify_inference_error() that maps error strings to categorized (error_type, message) pairs
  • Error categories detected: rate_limited, timeout, auth_error, budget_exhausted, provider_error, context_overflow, model_unavailable, inference (fallback)
  • Observability tags now use the classified error_type for better Sentry grouping

Frontend (app/src/providers/ChatRuntimeProvider.tsx):

  • Uses event.message from the server instead of the hardcoded generic constant

Frontend types (app/src/services/chatService.ts):

  • Widened ChatErrorEvent.error_type union to include all new categories

Closes #1506

Summary by CodeRabbit

  • Bug Fixes
    • Expanded error categorization to include rate limiting, authentication, provider, context overflow, model unavailability, and budget exhaustion error types.
    • Improved error deduplication logic and messaging precision for more accurate error reporting.

Review Change Stack

… went wrong'

Classify inference errors into actionable categories (rate_limited,
timeout, auth_error, provider_error, context_overflow, etc.) and pass
the specific message through to the UI instead of the generic fallback.

Changes:
- src/openhuman/channels/providers/web.rs: Add classify_inference_error()
  to categorize errors and produce specific user-facing messages; use
  the classified type in Sentry/observability reporting
- app/src/providers/ChatRuntimeProvider.tsx: Use event.message from
  the server instead of hardcoded generic constant
- app/src/services/chatService.ts: Widen ChatErrorEvent error_type
  union to include new categories

Closes tinyhumansai#1506
@PranavAgarkar07 PranavAgarkar07 requested a review from a team May 12, 2026 15:12
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 12, 2026

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: 4fe2a523-3deb-4b3d-afc3-cf130c72a4a0

📥 Commits

Reviewing files that changed from the base of the PR and between 15c7442 and 5cf1ff6.

📒 Files selected for processing (3)
  • app/src/providers/ChatRuntimeProvider.tsx
  • app/src/services/chatService.ts
  • src/openhuman/channels/providers/web.rs

📝 Walkthrough

Walkthrough

The PR implements categorized error messaging for chat failures. A new classification helper in Rust inspects error strings to map them to specific error types (rate-limited, auth failure, budget exhaustion, etc.) with appropriate user-facing messages. The TypeScript error event type expands to support these categories. The frontend's error deduplication and response dispatch logic now uses the actual categorized message instead of a hardcoded generic string.

Changes

Chat Error Categorization

Layer / File(s) Summary
Error type contract and classification helper
app/src/services/chatService.ts, src/openhuman/channels/providers/web.rs
ChatErrorEvent.error_type union expands to include rate_limited, auth_error, provider_error, context_overflow, model_unavailable, and budget_exhausted. New classify_inference_error helper examines lowercased error strings to select a category-specific (error_type, user_message) pair based on provider error substrings, falling back to generic inference.
Backend error reporting and event publishing
src/openhuman/channels/providers/web.rs
start_chat's run_chat_task error handler calls classify_inference_error, passes the classified_type to report_error metadata instead of always reporting "inference", and publishes the chat_error event with classified_message and classified_type.
Frontend error deduplication and dispatch
app/src/providers/ChatRuntimeProvider.tsx
onError handler resolves errorContent from the incoming event message or a default fallback, uses it for duplicate detection against the last thread message, and dispatches addInferenceResponse with the resolved error content instead of the fixed user-facing message.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client
  participant ChatRuntime as ChatRuntimeProvider
  participant ChatService as ChatService<br/>(Events)
  participant WebChannel as web.rs<br/>(Provider)
  participant Provider as AI Provider
  
  Client->>WebChannel: send message via start_chat
  WebChannel->>Provider: request inference
  Provider-->>WebChannel: error (e.g., "rate limit exceeded")
  WebChannel->>WebChannel: classify_inference_error() → <br/>("rate_limited", "Model is rate-limited...")
  WebChannel->>ChatService: publish chat_error with<br/>classified type & message
  ChatService->>ChatRuntime: onError(event)
  ChatRuntime->>ChatRuntime: resolve errorContent<br/>from event.message
  ChatRuntime->>ChatRuntime: check dedupe against<br/>last thread message
  ChatRuntime->>ChatRuntime: addInferenceResponse<br/>with errorContent
  ChatRuntime->>Client: render specific error
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • senamakel

Poem

🐰 A rabbit's error-sorting song:
Once every fault was dressed the same,
A generic blur without a name—
Now errors wear their colors bright,
Rate-limits, timeouts, each one right,
The chat flows clearer, crisp, and true! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 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: replacing generic error messages with specific ones in the chat interface.
Linked Issues check ✅ Passed The PR addresses the core objectives of #1506 by implementing error classification backend logic and displaying specific categorized error messages instead of generic text.
Out of Scope Changes check ✅ Passed All changes are scoped to error handling improvements across backend classification and frontend display, directly addressing the linked issue requirements.

✏️ 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.

❤️ Share

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

@graycyrus graycyrus self-requested a review May 12, 2026 16:41
)
} else if lower.contains("500") || lower.contains("internal server") || lower.contains("service unavailable") || lower.contains("503") {
(
"provider_error",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[critical] Fragile substring matching on HTTP status codes

Matching "500" and "503" as bare substrings in error text is dangerous. An error message like "context length exceeded: 500 tokens remaining" or "processed 500 items" would falsely classify as provider_error. Same risk with "429".

Fix: Match as status code patterns — e.g. "status 500", "http 500", "status: 500", "error 429" — not bare digit sequences.

(
"auth_error",
"There's an authentication issue with the AI provider. Please check your API key in settings.",
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[major] Budget error classified twice with conflicting messages

There's already a dedicated is_inference_budget_exceeded_error() (line ~579) with regex-based pattern matching that catches budget errors before they reach the Err path — it returns Ok with its own message. This adds a second budget check here with a different user-facing message:

  • Existing: "I don't have any budget available right now. Please top up your credits or choose a plan to continue."
  • New (here): "Insufficient credits. Please top up to continue."

If the existing handler catches it first (which it should), this branch is dead code. If it doesn't, users get inconsistent messaging. Either remove this budget_exhausted branch or unify the messages.

}
}

fn prompt_guard_user_message(action: PromptEnforcementAction) -> &'static str {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[major] No tests — will fail the coverage merge gate

classify_inference_error has 8 branches and 0 test coverage. The repo enforces ≥80% diff coverage via .github/workflows/coverage.yml. This will block merge.

Needs a #[cfg(test)] mod tests with cases for each classification branch (rate_limited, timeout, auth_error, budget_exhausted, provider_error, context_overflow, model_unavailable, and the fallback).

client_id_task, thread_id_task, request_id_task, err
);
let (classified_type, classified_message) = classify_inference_error(&err);
crate::core::observability::report_error(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[minor] Missing diagnostic logging for classification decision

Per repo convention (CLAUDE.md debug logging rules), the classification result should be logged so misclassifications are traceable in Sentry/logs:

log::debug!("[web-channel] classified inference error type={} from error={}", classified_type, &err[..err.len().min(200)]);

request_id?: string;
message: string;
error_type: 'network' | 'timeout' | 'tool_error' | 'inference' | 'cancelled';
error_type: 'network' | 'timeout' | 'tool_error' | 'inference' | 'cancelled' | 'rate_limited' | 'auth_error' | 'provider_error' | 'context_overflow' | 'model_unavailable' | 'budget_exhausted';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[minor] 11 variants on one line is hard to scan. Consider splitting:

error_type:
  | 'network' | 'timeout' | 'tool_error' | 'inference' | 'cancelled'
  | 'rate_limited' | 'auth_error' | 'provider_error'
  | 'context_overflow' | 'model_unavailable' | 'budget_exhausted';

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Chat window returns generic error instead of agent replies

2 participants