[FIX] Surface non_field_errors and name resources in 404s in the central DRF error path#2099
Conversation
When a form passes setBackendErrors, useExceptionHandler routed validation
errors to inline field rendering only and returned no alert. Errors whose
attr is non_field_errors (or has no attr) map to no input field, and
getBackendErrorDetail matches errors by attr, so these were never rendered
anywhere -> the request appeared to silently succeed.
This surfaced after the DRF 3.15 bump, where duplicate-create errors arrive
as nested non_field_errors ("...must make a unique set") instead of a
top-level detail string. Affected user-visible flows include duplicate LLM
profile name and table settings save.
Keep inline field errors as-is; additionally collect any non-field/attr-less
errors and show them in a toast. The toast relays only the backend-provided
detail (not the attr label), so nothing beyond the message itself is exposed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G8hAHc4HUo42zY1g9LAjKu
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThe PR updates frontend validation error handling to surface non-field errors as alerts and updates backend DRF exception handling to rewrite 404 error details before logging. ChangesFrontend validation alerts
Backend 404 detail enrichment
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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.
Actionable comments posted: 1
🤖 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.
Inline comments:
In `@frontend/src/hooks/useExceptionHandler.jsx`:
- Around line 54-56: The filter operation on `errors` assumes it is an array,
but it could be a truthy non-array object at runtime, which would cause
`.filter()` to throw an error. Before calling `.filter()` on the `errors`
variable in the nonFieldErrors assignment, add a guard to ensure `errors` is
actually an array. Check if `errors` is an array using Array.isArray(), and if
not, default to an empty array or the normalized array form before applying the
filter logic that checks for missing or "non_field_errors" attr values.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 803a2bea-8387-48ff-9c38-06ab1dd87252
📒 Files selected for processing (1)
frontend/src/hooks/useExceptionHandler.jsx
- Array.isArray guard before filter (avoids throw on non-array error payload) - Join multiple non-field messages with bullet, matching the other branch Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G8hAHc4HUo42zY1g9LAjKu
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G8hAHc4HUo42zY1g9LAjKu
DRF returns a bare "Not found." for every 404 across all apps, giving users no context. Enrich the detail in the central exception handler using the view's queryset model `verbose_name`, so 404s read "<Resource> not found." app-wide with no per-view work. Models can tune their label via `Meta.verbose_name`; views without a static `queryset` keep the generic message. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X8t7DFHq7Dj655kEywKk3K
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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.
Inline comments:
In `@backend/middleware/exception.py`:
- Around line 75-77: The exception handler in `backend/middleware/exception.py`
assumes `data.get("errors", [])` yields dict-like items, so `err.get("code")`
can crash if an item is not a dict. Update the loop in the exception handling
path to verify each `err` is a mapping before accessing `.get(...)`, and skip or
safely normalize any non-dict items so `not_found` handling in this block cannot
raise while handling an exception.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: af91ddb8-b56c-46ff-93e6-e15709cb6b2d
📒 Files selected for processing (2)
backend/middleware/exception.pybackend/middleware/test_exception.py
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X8t7DFHq7Dj655kEywKk3K
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X8t7DFHq7Dj655kEywKk3K
Frontend Lint Report (Biome)✅ All checks passed! No linting or formatting issues found. |
Unstract test resultsPer-group results
Critical paths
|
|



What
Two complementary fixes in the central DRF error path so API errors reach the user with usable text instead of silently vanishing or showing a context-free message.
1. Surface
non_field_errorsas a toast (frontend)useExceptionHandlernow surfaces validation errors that aren't bound to a form field (non_field_errors, or errors with noattr) as a toast, in addition to the existing inline field-error rendering.When a form passes
setBackendErrors, the handler routedvalidation_errorresponses to inline field rendering and returned no alert. Inline errors are matched to inputs byattr(viagetBackendErrorDetail), butnon_field_errorsmaps to no input — so those errors were rendered nowhere and no toast fired. The request looked like it silently succeeded. This became user-visible after the DRF 3.15 bump: duplicate-create errors arrive as nestednon_field_errors("...must make a unique set") instead of a top-leveldetail. Reproduced on duplicate LLM profile name and table settings save (QA, rc.343).2. Name the resource in 404s (backend)
DRF returns a bare
"Not found."for every 404 across all apps, giving the user no context (the symptom behind the lookup-not-visible toast from unstract-cloud #1570).drf_logging_exc_handlernow enriches the 404 detail using the view'squerysetmodelverbose_name, so errors read " not found." app-wide — no per-view or per-caller work, and future endpoints get it automatically.querysetattr (notget_queryset()) to avoid running view logic during error handling.model._meta.verbose_name(plain language) rather than the PascalCase class name; models can tune their label viaMeta.verbose_name.querysetkeep the generic message — no regression.Scope / safety
backend/middleware/test_exception.py(4 cases: enriched, no-queryset fallback, non-404 untouched, None-safe).🤖 Generated with Claude Code