feat: clear error messaging with upgrade prompts#233
Conversation
- Fix [object Object] error in DashboardHome.tsx (was showing raw object instead of message) - Add extractErrorMessage() helper for proper API error extraction - Add isUpgradeError() to detect REPO_TOO_LARGE/REPO_LIMIT_REACHED - Show toast with 'Join Waitlist' action button on limit errors - Reuse WaitlistModal for upgrade flow (no new components) - Add 'repos' to SKIP_DIRS in repo_validator.py (skip cloned repos)
|
@DevanshuNEU is attempting to deploy a commit to the Dev's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📝 WalkthroughWalkthroughExcluded cloned Changes
Sequence DiagramsequenceDiagram
actor User
participant DashboardHome as DashboardHome
participant API as Backend API
participant ErrorHelper as ErrorHelper
participant Toast as ToastService
participant Modal as WaitlistModal
User->>DashboardHome: add/import/start indexing
DashboardHome->>API: call add/import/index endpoint
API-->>DashboardHome: response (success or error)
DashboardHome->>ErrorHelper: extractErrorMessage / isUpgradeError
ErrorHelper-->>DashboardHome: {isUpgrade: bool, message}
alt Upgrade error
DashboardHome->>Toast: showUpgradeToast(message)
DashboardHome->>DashboardHome: set showUpgradeModal = true
DashboardHome->>Modal: render WaitlistModal (plan "Pro" — "$19/mo")
User->>Modal: interact (join/close)
Modal-->>DashboardHome: onClose
DashboardHome->>DashboardHome: set showUpgradeModal = false
else Non-upgrade error
DashboardHome->>DashboardHome: surface parsed error (throw/show)
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
backend/services/repo_validator.py (1)
79-104:⚠️ Potential issue | 🟠 Major
reposin SKIP_DIRS can skip the entire repo unintentionally.The skip check is applied to the absolute path parts. If the repo is stored under a parent folder named
repos(a common storage convention), every file will be skipped and size limits won’t be enforced. Consider applying SKIP_DIRS to the repo-relative path instead.🔧 Suggested fix (apply skips to repo-relative parts)
- if any(skip_dir in file_path.parts for skip_dir in self.SKIP_DIRS): + rel_parts = file_path.relative_to(repo_root).parts + if any(skip_dir in rel_parts for skip_dir in self.SKIP_DIRS): continue
🤖 Fix all issues with AI agents
In `@frontend/src/components/dashboard/DashboardHome.tsx`:
- Around line 36-41: In extractErrorMessage, guard against non-string values
from nested fields by checking typeof before returning err.detail.message or
err.message (e.g., only return when typeof === 'string'); if those fields are
objects or other types, convert them to a readable string (or fall back to the
provided fallback) so you don't return [object Object]; update the checks around
err?.detail?.message and err?.message in the extractErrorMessage function to
include these type checks and a safe fallback.
🧹 Nitpick comments (1)
frontend/src/components/dashboard/DashboardHome.tsx (1)
115-124: Consider DRYing the repeated upgrade‑toast blocks.The same toast payload is duplicated in four places; a small helper will keep messaging consistent and reduce drift.
♻️ Example refactor
+function showUpgradeToast(err: any, fallback: string, onJoin: () => void) { + toast.error(extractErrorMessage(err, fallback), { + description: 'Join the Pro waitlist for higher limits', + action: { label: 'Join Waitlist', onClick: onJoin } + }) +}- if (isUpgradeError(err)) { - toast.error(extractErrorMessage(err, 'Repository too large'), { - description: 'Join the Pro waitlist for higher limits', - action: { label: 'Join Waitlist', onClick: () => setShowUpgradeModal(true) } - }) - return - } + if (isUpgradeError(err)) { + showUpgradeToast(err, 'Repository too large', () => setShowUpgradeModal(true)) + return + }Apply similarly in the other upgrade‑error blocks.
Also applies to: 136-146, 185-193, 206-214
Backend: - Use repo-relative paths for SKIP_DIRS check (fixes false skip when repo is stored in folder named 'repos', 'dist', etc.) Frontend: - Add type guards to extractErrorMessage() - check typeof before using - Add showUpgradeToast() helper - DRYs 4 duplicate toast blocks - Add JSON.stringify fallback for object error details
Bug fix: Settings page 'Delete All' was calling non-existent endpoint
Backend:
- Add DELETE /repos/{repo_id} route with ownership verification
- Add repo_manager.delete_repo() method that:
- Deletes from Supabase (cascades to embeddings, dependencies)
- Cleans up local clone directory
- Removes from in-memory cache
This completes the Settings page danger zone functionality.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@backend/services/repo_manager.py`:
- Around line 180-182: The deletion code references a non-existent in-memory
cache attribute self.repos causing AttributeError; either remove the cache
cleanup block from the delete flow or add an explicit cache initialization in
RepositoryManager.__init__ (e.g., self.repos = {}) if you intend to maintain an
in-memory cache; update the code path that performs deletion (the block shown
that checks "if repo_id in self.repos: del self.repos[repo_id]") to match that
decision and ensure no AttributeError occurs at runtime.
🧹 Nitpick comments (1)
backend/services/repo_manager.py (1)
168-169: Consider wrapping database deletion in try/except for clearer error handling.If
self.db.delete_repository(repo_id)throws an exception, it will propagate up without context. While the route handler catches this, wrapping it here would allow for consistent logging and could distinguish between "not found" (return False) and "deletion failed" (raise or return False with logging).♻️ Optional: Add explicit error handling for DB deletion
# Delete from database (cascades to embeddings, dependencies, etc.) - self.db.delete_repository(repo_id) + try: + self.db.delete_repository(repo_id) + except Exception as e: + logger.error("Failed to delete repository from database", repo_id=repo_id, error=str(e)) + raise
- Handle both FastAPI wrapped ({detail: {...}}) and unwrapped errors
- isUpgradeError now checks err.detail.error OR err.error
- extractErrorMessage prioritizes .message field, truncates long JSON
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@frontend/src/components/dashboard/DashboardHome.tsx`:
- Around line 45-49: The JSON.stringify call on detail can throw for circular
objects; wrap the serialization in a try/catch or replace it with a small
safeStringify helper that detects cycles. Update the code around the detail
handling (the block that reads const msg = detail.message || detail.error and
returns JSON.stringify(detail).slice(0, 200)) to attempt JSON.stringify(detail)
inside try and on error fall back to a non-throwing representation (e.g.,
iterate with a Set to omit circular refs or return String(detail) or a short
'[Circular]' marker), then slice to 200 chars before returning; this preserves
the existing behavior but prevents crashes for circular error objects.
AttributeError: 'RepositoryManager' object has no attribute 'repos' There's no in-memory cache, only database operations.
Root cause: except Exception caught HTTPException(403, REPO_TOO_LARGE)
and re-raised as HTTPException(400, str(e)) which produced '403: {...}'
Now HTTPExceptions are re-raised as-is so frontend gets proper 403 with
structured detail object.
- Create UpgradeLimitModal component with: - Clear error message display - Free vs Pro limit comparison - Built-in waitlist signup form - 30% early bird discount callout - Stays visible until user dismisses - Update DashboardHome to use modal instead of toast - Shows repo name and specific error reason - Much better UX for upgrade prompts
CodeRabbit feedback - JSON.stringify can throw on circular objects. Wrap in try-catch, fallback to String() on error.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Summary
Fixes the
[object Object]error display bug and adds proper upgrade prompts when users hit tier limits.Changes
Frontend (
DashboardHome.tsx)err.detailobject as string → now properly extractserr.detail.messageextractErrorMessage()- handles nested API error responsesisUpgradeError()- detectsREPO_TOO_LARGE/REPO_LIMIT_REACHEDcodesWaitlistModal: No new components, just reuse existing modal for upgrade promptBackend (
repo_validator.py)'repos'toSKIP_DIRS- prevents counting cloned repositories when indexingUser Experience
Before:
After:
Testing
reposin SKIP_DIRS verifiedSummary by CodeRabbit
New Features
Bug Fixes
✏️ Tip: You can customize this high-level summary in your review settings.