Skip to content

Handle 404 errors gracefully when viewing deleted entities in UI#1829

Open
queelius wants to merge 1 commit intocloudamqp:mainfrom
queelius:fix/889-handle-deleted-entities
Open

Handle 404 errors gracefully when viewing deleted entities in UI#1829
queelius wants to merge 1 commit intocloudamqp:mainfrom
queelius:fix/889-handle-deleted-entities

Conversation

@queelius
Copy link
Copy Markdown

Summary

Fixes #889

When an entity (exchange, queue, connection, etc.) is deleted while its management UI detail page is open, the UI previously showed the unhelpful error "Something went wrong: Error fetching data: [object Object]". This PR makes the UI handle 404 responses gracefully:

  • Entity detail pages now catch 404 errors, stop the periodic refresh interval, and replace the page content with a clear "not found" message and a link back to the entity list page
  • Table data sources now emit a distinct not_found event on 404, which the table renders as a user-friendly message instead of the generic error
  • Error serialization is fixed so error objects always have a message property (preventing [object Object] in string concatenation)

Root cause

The error object created in http.js on non-OK responses had no message property. When the datasource caught this error and tried to emit it, the object was passed through to toggleDisplayError() which concatenated it into a string, producing [object Object]. Additionally, none of the entity detail pages (exchange.js, queue.js, etc.) had .catch() handlers for their periodic API fetch calls.

Files changed

  • static/js/http.js - Add message property to error objects
  • static/js/datasource.js - Emit not_found event on 404; ensure error messages are always strings
  • static/js/table.js - Handle not_found event; fix error display fallback
  • static/js/dom.js - Add showEntityNotFound() helper function
  • static/js/exchange.js - Handle 404 on entity fetch
  • static/js/queue.js - Handle 404 on entity fetch
  • static/js/connection.js - Handle 404 on entity fetch
  • static/js/channel.js - Handle 404 on entity fetch
  • static/js/vhost.js - Handle 404 on entity fetch
  • static/js/user.js - Handle 404 on entity fetch
  • static/js/stream.js - Handle 404 on entity fetch

Test plan

  • Open an exchange detail page, delete the exchange via AMQP, verify the UI shows "Exchange not found" with a link to the exchanges list
  • Open a queue detail page, delete the queue, verify the UI shows "Queue not found" with a link to the queues list
  • Verify the same behavior for connections, channels, vhosts, users, and streams
  • Verify the bindings table on exchange/queue pages shows "This resource no longer exists" instead of [object Object]
  • Verify normal (non-404) errors still display correctly
  • Run npx standard static/js to verify linting passes

🤖 Generated with Claude Code

…ent UI

When an entity (exchange, queue, connection, channel, vhost, user, or
stream) is deleted while its management UI detail page is open, the UI
now shows a clear "not found" message with a link back to the list page,
instead of the unhelpful "Something went wrong: Error fetching data:
[object Object]" error.

Changes:
- http.js: Add `message` property to error objects so they serialize to
  readable strings instead of [object Object]
- datasource.js: Emit a distinct `not_found` event on 404 responses,
  and ensure generic errors always pass a string message
- table.js: Handle the `not_found` event with a user-friendly message,
  and fix error display to fall back to string conversion
- dom.js: Add `showEntityNotFound()` helper that replaces page content
  with a "not found" card and a link back to the entity list
- Entity detail pages (exchange, queue, connection, channel, vhost,
  user, stream): Catch 404 errors from the periodic fetch, stop the
  refresh interval, and show the not-found message

Fixes cloudamqp#889

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@queelius queelius requested a review from a team as a code owner March 25, 2026 10:34
Copilot AI review requested due to automatic review settings March 25, 2026 10:34
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR improves the management UI’s behavior when a currently-viewed entity is deleted, by handling 404 responses explicitly and presenting user-friendly “not found” messaging instead of generic/opaque errors.

Changes:

  • Add a shared DOM.showEntityNotFound() helper that replaces the page content with an entity-specific “not found” view and a back link.
  • Update multiple entity detail pages (exchange/queue/stream/connection/channel/user/vhost) to catch 404s, stop refresh intervals where applicable, and show the not-found view.
  • Improve error propagation/display by (a) ensuring HTTP error objects have a message, and (b) adding a datasource not_found event that tables can render as a friendly message.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
static/js/http.js Ensures non-OK HTTP error objects include a usable message (avoids [object Object] concatenation).
static/js/datasource.js Emits a distinct not_found event on 404 and normalizes emitted error text.
static/js/table.js Renders datasource 404s as a user-friendly message; improves error-string fallback.
static/js/dom.js Adds showEntityNotFound() helper to replace main content with a not-found view.
static/js/exchange.js Stops periodic exchange refresh and shows not-found view on 404.
static/js/queue.js Stops periodic queue refresh and shows not-found view on 404.
static/js/stream.js Stops periodic stream refresh and shows not-found view on 404.
static/js/connection.js Stops periodic connection refresh and shows not-found view on 404.
static/js/channel.js Stops periodic channel refresh and shows not-found view on 404.
static/js/user.js Shows not-found view on 404 when loading user details.
static/js/vhost.js Shows not-found view on 404 when loading vhost details.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +38 to 42
toggleDisplayError(id, 'Error fetching data: ' + (error.detail || error))
})
dataSource.on('not_found', () => {
toggleDisplayError(id, 'This resource no longer exists. It may have been deleted.')
})
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

toggleDisplayError() assumes the ${id}-error element exists. After DOM.showEntityNotFound() clears <main>, datasource reload callbacks can still fire and these handlers will throw when the error element is gone. Please guard against missing elements (either inside toggleDisplayError() or before calling it) to prevent runtime exceptions after switching to the not-found view.

Copilot uses AI. Check for mistakes.
Comment on lines 145 to 160
reload (args) {
clearTimeout(this._reloadTimer)
return this._reload(args).then(resp => {
this._enqueueReload()
this.items = resp
return resp
}).catch(err => {
this._enqueueReload()
if (err.status === 401) { return }
if (err.message) {
this.emit('error', err.message)
} else {
this.emit('error', err)
if (err.status === 404) {
this.emit('not_found')
return
}
const message = err.message || err.reason || String(err)
this.emit('error', message)
})
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

DataSource.reload() currently calls _enqueueReload() before checking for err.status === 404, so a 404 will still schedule another reload and keep polling a permanently deleted resource. Consider skipping _enqueueReload() for 404 (and clearing any pending timer) so not_found is emitted once and auto-reload stops for that datasource.

Copilot uses AI. Check for mistakes.
dataSource.on('error', error => {
console.log(error)
toggleDisplayError(id, 'Error fetching data: ' + error.detail)
toggleDisplayError(id, 'Error fetching data: ' + (error.detail || error))
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

In the table error handler, (error.detail || error) can still stringify to [object CustomEvent]/[object Object] if detail is falsy or not a string. Safer is to use a nullish check and explicitly coerce the chosen value to a string before concatenation.

Suggested change
toggleDisplayError(id, 'Error fetching data: ' + (error.detail || error))
const errorDetail = error?.detail ?? error
toggleDisplayError(id, 'Error fetching data: ' + String(errorDetail))

Copilot uses AI. Check for mistakes.
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.

Handle 404 errors gracefully when viewing deleted entities in management UI

2 participants