Summary
Components and hooks across @itwin/imodel-browser-react and @itwin/manage-versions-react have two distinct classes of error-handling problems, depending on whether the failing operation is a primary data load or a secondary background action.
Specific Problems
Primary data fetches — error state surfaces in UI, but recovery is impossible
| Location |
Behavior |
useIModelData |
On fetch failure, sets DataStatus.FetchFailed and calls console.error(e) |
useITwinData |
Same |
ManageVersions getVersions |
Sets RequestStatus.Failed (silently — error object is discarded in the .catch) |
ManageVersions getChangesets |
Same |
These do surface in the UI (an error string is shown), but:
- The user has no "Try again" button. The grid is stuck until the consumer unmounts and remounts the component.
- No
onError callback is exposed, so the consumer cannot observe what went wrong or log it with context.
ManageVersions discards the error object entirely in the .catch(() => setVersionStatus(RequestStatus.Failed)) pattern, losing the stack trace.
Secondary/background operations — truly silently swallowed
| Location |
Behavior |
useITwinFavorites — add, remove, and initial fetch |
Caught, console.error(error) called, nothing else. No user feedback. |
IModelGrid.tsx — add to recents |
Caught, console.error("Failed to add iModel to recents", e) called. |
iModelApi.ts — removeIModelFromRecents |
Same. |
ManageVersions.tsx — user data fetch |
.catch(() => { console.error("Unable to fetch users data"); }) — error object discarded. |
VersionsTab.tsx — expand row (fetch changesets) |
.catch(() => { console.error("Failed to get Changesets"); }) — error object discarded, sub-rows silently stay empty. |
These are fire-and-forget or best-effort operations where swallowing is sometimes intentional, but there is zero user feedback even for operations the user explicitly triggered (e.g., adding/removing a favorite).
Recommended Fix
1. Add "Try again" / retry actions to primary error states.
NoResults (imodel-browser) and the empty-table overlay in manage-versions should accept an optional onRetry callback. When the status is an error state, render a "Try again" button alongside the error message. The refetchITwins / refetchIModels functions already exist — they just need to be wired into the error UI.
2. Expose an onError callback on data hooks.
useIModelData, useITwinData, and the favorites hooks should accept an onError?: (error: unknown) => void option so consumers can observe failures and log them with appropriate context.
3. Preserve the error object in .catch() handlers.
Several catch handlers receive no argument at all, losing the stack trace and error message entirely. At minimum, pass the error to the log call: .catch((e) => setVersionStatus(RequestStatus.Failed)) → .catch((e) => { setVersionStatus(RequestStatus.Failed); log?.(e); }).
4. Switch non-critical background operations to console.warn.
Network failures on best-effort calls (add/remove recents, user display-name enrichment) are expected, transient events. console.error implies a programming mistake and triggers error monitoring tools. These should use console.warn.
5. Surface user-triggered secondary failures.
When a user explicitly triggers an action (add/remove favorite), a silent console.error is not acceptable. These should at minimum call an onError callback or show a toast.
Summary
Components and hooks across
@itwin/imodel-browser-reactand@itwin/manage-versions-reacthave two distinct classes of error-handling problems, depending on whether the failing operation is a primary data load or a secondary background action.Specific Problems
Primary data fetches — error state surfaces in UI, but recovery is impossible
useIModelDataDataStatus.FetchFailedand callsconsole.error(e)useITwinDataManageVersionsgetVersionsRequestStatus.Failed(silently — error object is discarded in the.catch)ManageVersionsgetChangesetsThese do surface in the UI (an error string is shown), but:
onErrorcallback is exposed, so the consumer cannot observe what went wrong or log it with context.ManageVersionsdiscards the error object entirely in the.catch(() => setVersionStatus(RequestStatus.Failed))pattern, losing the stack trace.Secondary/background operations — truly silently swallowed
useITwinFavorites— add, remove, and initial fetchconsole.error(error)called, nothing else. No user feedback.IModelGrid.tsx— add to recentsconsole.error("Failed to add iModel to recents", e)called.iModelApi.ts—removeIModelFromRecentsManageVersions.tsx— user data fetch.catch(() => { console.error("Unable to fetch users data"); })— error object discarded.VersionsTab.tsx— expand row (fetch changesets).catch(() => { console.error("Failed to get Changesets"); })— error object discarded, sub-rows silently stay empty.These are fire-and-forget or best-effort operations where swallowing is sometimes intentional, but there is zero user feedback even for operations the user explicitly triggered (e.g., adding/removing a favorite).
Recommended Fix
1. Add "Try again" / retry actions to primary error states.
NoResults(imodel-browser) and the empty-table overlay in manage-versions should accept an optionalonRetrycallback. When the status is an error state, render a "Try again" button alongside the error message. TherefetchITwins/refetchIModelsfunctions already exist — they just need to be wired into the error UI.2. Expose an
onErrorcallback on data hooks.useIModelData,useITwinData, and the favorites hooks should accept anonError?: (error: unknown) => voidoption so consumers can observe failures and log them with appropriate context.3. Preserve the error object in
.catch()handlers.Several catch handlers receive no argument at all, losing the stack trace and error message entirely. At minimum, pass the error to the log call:
.catch((e) => setVersionStatus(RequestStatus.Failed))→.catch((e) => { setVersionStatus(RequestStatus.Failed); log?.(e); }).4. Switch non-critical background operations to
console.warn.Network failures on best-effort calls (add/remove recents, user display-name enrichment) are expected, transient events.
console.errorimplies a programming mistake and triggers error monitoring tools. These should useconsole.warn.5. Surface user-triggered secondary failures.
When a user explicitly triggers an action (add/remove favorite), a silent
console.erroris not acceptable. These should at minimum call anonErrorcallback or show a toast.