Skip to content

feat: clear error messaging with upgrade prompts#233

Merged
DevanshuNEU merged 8 commits into
OpenCodeIntel:mainfrom
DevanshuNEU:feat/clear-error-messaging
Jan 30, 2026
Merged

feat: clear error messaging with upgrade prompts#233
DevanshuNEU merged 8 commits into
OpenCodeIntel:mainfrom
DevanshuNEU:feat/clear-error-messaging

Conversation

@DevanshuNEU

@DevanshuNEU DevanshuNEU commented Jan 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes the [object Object] error display bug and adds proper upgrade prompts when users hit tier limits.

Changes

Frontend (DashboardHome.tsx)

  • Fix error extraction: Was showing raw err.detail object as string → now properly extracts err.detail.message
  • Add helper functions:
    • extractErrorMessage() - handles nested API error responses
    • isUpgradeError() - detects REPO_TOO_LARGE / REPO_LIMIT_REACHED codes
  • Upgrade flow: When hitting limits, show toast with "Join Waitlist" action button
  • Reuse WaitlistModal: No new components, just reuse existing modal for upgrade prompt

Backend (repo_validator.py)

  • Add 'repos' to SKIP_DIRS - prevents counting cloned repositories when indexing

User Experience

Before:

❌ Failed to add repository
   [object Object]

After:

⚠️ Repository too large (2,500 files)
   Join the Pro waitlist for higher limits
   [Join Waitlist →]

Testing

  • Frontend builds successfully
  • Backend repos in SKIP_DIRS verified
  • Error extraction handles all cases (string, nested object, fallback)

Summary by CodeRabbit

  • New Features

    • Pro waitlist modal and reusable "Join Waitlist" upgrade toast flow.
    • Repository deletion endpoint allowing users to remove repos from their account (including local clone cleanup).
  • Bug Fixes

    • Improved error parsing and upgrade-aware messages during repo add/import and indexing flows.
    • Excluded cloned repository directories from code-file scanning to reduce false positives.

✏️ Tip: You can customize this high-level summary in your review settings.

- 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)
@vercel

vercel Bot commented Jan 30, 2026

Copy link
Copy Markdown

@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.

@coderabbitai

coderabbitai Bot commented Jan 30, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@DevanshuNEU has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 3 minutes and 29 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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.

📝 Walkthrough

Walkthrough

Excluded cloned repos directories from code scans via repo-relative skipping, added a repository deletion API and manager method to remove local clones and DB records, and added upgrade-aware error helpers, toasts, and a WaitlistModal in DashboardHome for add/import/indexing flows.

Changes

Cohort / File(s) Summary
Repo validation
backend/services/repo_validator.py
Added 'repos' to SKIP_DIRS and changed skip checks to use repository-relative path parts (rel_parts) instead of absolute file_path.parts to avoid false positives when parent directories share names.
Repository deletion API & manager
backend/routes/repos.py, backend/services/repo_manager.py
Added DELETE /repos/{repo_id} endpoint (delete_repository) and RepositoryManager.delete_repo(repo_id) to remove local clone files, then delete DB records, clear cache/log actions, and return success/failure; preserves existing auth and error handling.
Upgrade UX & error handling
frontend/src/components/dashboard/DashboardHome.tsx
Added extractErrorMessage, isUpgradeError, and showUpgradeToast helpers; introduced showUpgradeModal state and rendered WaitlistModal (plan "Pro" — "$19/mo"); integrated upgrade-aware handling at repo add, indexing start, and GitHub import flows to show toast/modal for upgrade-related errors while preserving normal success flows.
Manifest / metadata
manifest_file, package.json
Updated project manifest/package metadata entries (minor referenced updates).

Sequence Diagram

sequenceDiagram
    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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped through code and tidied lanes,
Skipped cloned burrows, cleared the chains,
Toasted upgrades with a hopeful cheer,
Opened a modal — carrots near,
Now the dashboard hums, all clean again.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: clear error messaging with upgrade prompts' directly aligns with the main changes: adding error message extraction, upgrade error detection, and upgrade prompt modals in the frontend, plus improving error handling in the backend.
Docstring Coverage ✅ Passed Docstring coverage is 90.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

repos in 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

Comment thread frontend/src/components/dashboard/DashboardHome.tsx
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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Comment thread backend/services/repo_manager.py Outdated
- Handle both FastAPI wrapped ({detail: {...}}) and unwrapped errors
- isUpgradeError now checks err.detail.error OR err.error
- extractErrorMessage prioritizes .message field, truncates long JSON

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Comment thread frontend/src/components/dashboard/DashboardHome.tsx Outdated
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.
@vercel

vercel Bot commented Jan 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
opencodeintel Ready Ready Preview, Comment Jan 30, 2026 2:28am

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.

1 participant