Skip to content
This repository was archived by the owner on May 13, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/server/static-react/src/api/core/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,21 @@ export class ApiError extends Error {
if (this.isNetworkError) {
return ERROR_MESSAGES.NETWORK_ERROR;
}

if (this.isTimeoutError) {
return ERROR_MESSAGES.TIMEOUT_ERROR;
}

// Prefer the server-supplied descriptive message over the generic constant
// for HTTP errors. ErrorFactory.fromResponse fills `this.message` with
// `errorData.message` / `errorData.error` (e.g. structured 400 payloads
// like "Field 'title' not on schema 'X'", or a 404 body's "schema not
// found") — that text is what the user can actually act on. The synthetic
// `HTTP <status>` fallback is filtered out so we don't surface "HTTP 404".
if (this.message && this.status > 0 && !/^HTTP \d+$/.test(this.message)) {
return this.message;
}

switch (this.status) {
case HTTP_STATUS_CODES.UNAUTHORIZED:
return ERROR_MESSAGES.AUTHENTICATION_ERROR;
Expand Down
9 changes: 7 additions & 2 deletions src/server/static-react/src/components/StatusSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { systemClient } from '../api/clients/systemClient'
import { ingestionClient } from '../api/clients'
import type { IngestionProgress } from '../api/clients/ingestionClient'
import { usePolling } from '../hooks/usePolling'
import { isNetworkError } from '../api/core/errors'
import { toErrorMessage } from '../utils/schemaUtils'

type ProgressJob = IngestionProgress & { job_type?: string }

Expand Down Expand Up @@ -76,8 +78,11 @@ function StatusSection() {
setIsResetting(false)
}
} catch (error) {
const msg = error instanceof Error ? error.message : String(error)
setResetResult({ type: 'error', message: `Network error: ${msg}` })
const msg = toErrorMessage(error)
setResetResult({
type: 'error',
message: isNetworkError(error) ? `Network error: ${msg}` : msg,
})
setShowConfirmDialog(false)
setIsResetting(false)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { FieldsTable } from '../StructuredResults'
import SchemaName from '../shared/SchemaName'
import ShareRecordModal from '../ShareRecordModal'
import { ArrowUpTrayIcon } from '@heroicons/react/24/outline'
import { getFieldNames, toggleSetItem } from '../../utils/schemaUtils'
import { getFieldNames, toErrorMessage, toggleSetItem } from '../../utils/schemaUtils'
import {
keyId,
keyLabel,
Expand Down Expand Up @@ -186,7 +186,7 @@ export default function DataBrowserTab() {
setSchemaErrors((p) => ({ ...p, [name]: res.error || 'Failed to fetch keys' }))
}
} catch (e) {
setSchemaErrors((p) => ({ ...p, [name]: (e instanceof Error ? e.message : String(e)) || 'Network error' }))
setSchemaErrors((p) => ({ ...p, [name]: toErrorMessage(e) || 'Failed to fetch keys' }))
} finally {
setSchemaLoading((p) => ({ ...p, [name]: false }))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ function ProfileCard({ result, onConnect }: ProfileCardProps) {
onConnect({ error: res.error || 'Connect failed' })
}
} catch (e) {
onConnect({ error: toErrorMessage(e) || 'Network error' })
onConnect({ error: toErrorMessage(e) || 'Connect failed' })
} finally {
setSending(false)
}
Expand Down Expand Up @@ -235,7 +235,7 @@ export default function DiscoveryBrowseTab({ onResult }: DiscoveryBrowseTabProps
setSearchError(res.error || 'Search failed')
}
} catch (e) {
setSearchError(toErrorMessage(e) || 'Network error')
setSearchError(toErrorMessage(e) || 'Search failed')
} finally {
setSearching(false)
}
Expand Down
3 changes: 2 additions & 1 deletion src/server/static-react/src/components/tabs/FeedTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useState, useCallback } from 'react'
import { useAppSelector } from '../../store/hooks'
import { createApiClient } from '../../api/core/client'
import { API_ENDPOINTS } from '../../api/endpoints'
import { toErrorMessage } from '../../utils/schemaUtils'

const apiClient = createApiClient()

Expand Down Expand Up @@ -78,7 +79,7 @@ export default function FeedTab() {
setTotal(data?.total || 0)
setFetched(true)
} catch (err) {
setError((err instanceof Error ? err.message : null) || 'Network error')
setError(toErrorMessage(err) || 'Failed to fetch feed')
} finally {
setLoading(false)
}
Expand Down
4 changes: 2 additions & 2 deletions src/server/static-react/src/components/tabs/MyProfileTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ export default function MyProfileTab({ onResult }: MyProfileTabProps) {
onResult?.({ error: res.error || 'Detection failed' })
}
} catch (e) {
onResult?.({ error: toErrorMessage(e) || 'Network error' })
onResult?.({ error: toErrorMessage(e) || 'Detection failed' })
} finally {
setDetecting(false)
}
Expand All @@ -358,7 +358,7 @@ export default function MyProfileTab({ onResult }: MyProfileTabProps) {
onResult?.({ error: res.error || 'Toggle failed' })
}
} catch (e) {
onResult?.({ error: toErrorMessage(e) || 'Network error' })
onResult?.({ error: toErrorMessage(e) || 'Toggle failed' })
} finally {
setToggling(false)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ export default function NativeIndexTab({ onResult }: NativeIndexTabProps) {
onResult({ error: res.error || 'Search failed', status: res.status })
}
} catch (e) {
const msg = toErrorMessage(e)
setError(msg || 'Network error')
onResult({ error: msg || 'Network error' })
const msg = toErrorMessage(e) || 'Search failed'
setError(msg)
onResult({ error: msg })
} finally {
setIsSearching(false)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export default function WordGraphTab() {
setError(res.error || 'Search failed')
}
} catch (e) {
setError(toErrorMessage(e) || 'Network error')
setError(toErrorMessage(e) || 'Search failed')
} finally {
setIsSearching(false)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export default function ConnectionRequestsPanel({ onResult }: ConnectionRequests
onResult({ error: res.error || `Failed to ${action}` })
}
} catch (e) {
onResult({ error: toErrorMessage(e) || 'Network error' })
onResult({ error: toErrorMessage(e) || 'Failed to respond' })
} finally {
setResponding(null)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ export default function FaceSearchPanel({ onResult }: FaceSearchPanelProps) {
onResult({ error: res.error || 'Face search failed' })
}
} catch (e) {
const msg = toErrorMessage(e)
setError(msg || 'Network error')
onResult({ error: msg || 'Network error' })
const msg = toErrorMessage(e) || 'Face search failed'
setError(msg)
onResult({ error: msg })
} finally {
setSearching(false)
}
Expand All @@ -138,7 +138,7 @@ export default function FaceSearchPanel({ onResult }: FaceSearchPanelProps) {
onResult({ error: res.error || 'Connect failed' })
}
} catch (e) {
onResult({ error: toErrorMessage(e) || 'Network error' })
onResult({ error: toErrorMessage(e) || 'Connect failed' })
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default function InterestsPanel({ onResult }: InterestsPanelProps) {
setLoadError(res.error || 'Failed to load interests')
}
} catch (e) {
setLoadError(toErrorMessage(e) || 'Network error')
setLoadError(toErrorMessage(e) || 'Failed to load interests')
} finally {
setLoading(false)
}
Expand All @@ -42,7 +42,7 @@ export default function InterestsPanel({ onResult }: InterestsPanelProps) {
onResult({ error: res.error || 'Toggle failed' })
}
} catch (e) {
onResult({ error: toErrorMessage(e) || 'Network error' })
onResult({ error: toErrorMessage(e) || 'Toggle failed' })
}
}

Expand All @@ -57,7 +57,7 @@ export default function InterestsPanel({ onResult }: InterestsPanelProps) {
onResult({ error: res.error || 'Detection failed' })
}
} catch (e) {
onResult({ error: toErrorMessage(e) || 'Network error' })
onResult({ error: toErrorMessage(e) || 'Detection failed' })
} finally {
setDetecting(false)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default function PeopleLikeYouPanel({ onResult }: PeopleLikeYouPanelProps
}
}
} catch (e) {
const msg = toErrorMessage(e) || 'Network error'
const msg = toErrorMessage(e) || 'Failed to load similar profiles'
setError(msg)
if (isLocalModeError(msg)) {
localModeRef.current = true
Expand Down Expand Up @@ -74,7 +74,7 @@ export default function PeopleLikeYouPanel({ onResult }: PeopleLikeYouPanelProps
onResult({ error: res.error || 'Connect failed' })
}
} catch (e) {
onResult({ error: toErrorMessage(e) || 'Network error' })
onResult({ error: toErrorMessage(e) || 'Connect failed' })
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ export default function SearchPanel({ onResult }: SearchPanelProps) {
onResult({ error: res.error || 'Search failed' })
}
} catch (e) {
const msg = toErrorMessage(e)
setError(msg || 'Network error')
onResult({ error: msg || 'Network error' })
const msg = toErrorMessage(e) || 'Search failed'
setError(msg)
onResult({ error: msg })
} finally {
setSearching(false)
}
Expand All @@ -76,7 +76,7 @@ export default function SearchPanel({ onResult }: SearchPanelProps) {
onResult({ error: res.error || 'Connect failed' })
}
} catch (e) {
onResult({ error: toErrorMessage(e) || 'Network error' })
onResult({ error: toErrorMessage(e) || 'Connect failed' })
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default function SharedEventsPanel({ onResult }: SharedEventsPanelProps)
setError(statusRes.error || 'Failed to load calendar sharing status')
}
} catch (e) {
setError(toErrorMessage(e) || 'Network error')
setError(toErrorMessage(e) || 'Failed to load calendar sharing status')
} finally {
setLoading(false)
}
Expand Down Expand Up @@ -65,7 +65,7 @@ export default function SharedEventsPanel({ onResult }: SharedEventsPanelProps)
onResult({ error: res.error || 'Failed to toggle calendar sharing' })
}
} catch (e) {
onResult({ error: toErrorMessage(e) || 'Network error' })
onResult({ error: toErrorMessage(e) || 'Failed to toggle calendar sharing' })
} finally {
setToggling(false)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useCallback, useEffect, useState } from 'react'
import { listIdentities, type IdentityAuditRow } from '../../../api/clients/fingerprintsClient'
import { toErrorMessage } from '../../../utils/schemaUtils'

/**
* "Identities" audit panel — surfaces every Identity record on this
Expand Down Expand Up @@ -29,7 +30,7 @@ export default function ImportedIdentitiesPanel() {
setError(res.error ?? 'Failed to load identities')
}
} catch (e) {
setError((e as Error)?.message ?? 'Network error')
setError(toErrorMessage(e) || 'Failed to load identities')
} finally {
setLoading(false)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
resolveIngestionError,
type IngestionErrorView,
} from '../../../api/clients/fingerprintsClient'
import { toErrorMessage } from '../../../utils/schemaUtils'

/**
* Failed records panel. Renders unresolved IngestionError rows so the
Expand Down Expand Up @@ -33,7 +34,7 @@ export default function IngestionErrorsPanel() {
setError(res.error ?? 'Failed to load ingestion errors')
}
} catch (e) {
setError((e as Error)?.message ?? 'Network error')
setError(toErrorMessage(e) || 'Failed to load ingestion errors')
} finally {
setLoading(false)
}
Expand Down Expand Up @@ -63,7 +64,7 @@ export default function IngestionErrorsPanel() {
setError(res.error ?? `Failed to ${resolved ? 'dismiss' : 'restore'}`)
}
} catch (e) {
setError((e as Error)?.message ?? 'Network error')
setError(toErrorMessage(e) || 'Failed to update ingestion error')
} finally {
setBusyId(null)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
type MyIdentityCardResponse,
} from '../../../api/clients/fingerprintsClient'
import { listContacts, type Contact } from '../../../api/clients/trustClient'
import { toErrorMessage } from '../../../utils/schemaUtils'

type AttachStage = 'idle' | 'camera' | 'detecting' | 'saving'

Expand Down Expand Up @@ -93,7 +94,7 @@ export default function MyIdentityCardPanel() {
setError(res.error ?? 'Failed to load identity card')
}
} catch (e) {
setError((e as Error)?.message ?? 'Network error')
setError(toErrorMessage(e) || 'Failed to load identity card')
} finally {
setLoading(false)
}
Expand Down Expand Up @@ -134,7 +135,7 @@ export default function MyIdentityCardPanel() {
setSaveError(res.error ?? 'Failed to reissue identity card')
}
} catch (e) {
setSaveError((e as Error)?.message ?? 'Network error')
setSaveError(toErrorMessage(e) || 'Failed to reissue identity card')
} finally {
setSaving(false)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
type ResolveDiagnostics,
} from '../../../api/clients/fingerprintsClient'
import { ErrorMessage } from '../../shared/ErrorMessage'
import { toErrorMessage } from '../../../utils/schemaUtils'

type SortMode = 'recent' | 'name_asc' | 'mentions_desc' | 'trust_tier_desc'

Expand Down Expand Up @@ -160,7 +161,7 @@ export default function PersonasPanel() {
setError(res.error ?? 'Failed to load personas')
}
} catch (e) {
setError((e as Error)?.message ?? 'Network error')
setError(toErrorMessage(e) || 'Failed to load personas')
} finally {
setLoading(false)
}
Expand Down Expand Up @@ -190,7 +191,7 @@ export default function PersonasPanel() {
})
.catch((e: unknown) => {
if (!cancelled) {
setDetailError((e as Error)?.message ?? 'Network error')
setDetailError(toErrorMessage(e) || 'Failed to load persona')
setDetail(null)
}
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
listReceivedCards,
type ReceivedCardView,
} from '../../../api/clients/fingerprintsClient'
import { toErrorMessage } from '../../../utils/schemaUtils'

type ActionFlag = 'accept' | 'dismiss' | null

Expand Down Expand Up @@ -52,7 +53,7 @@ export default function ReceivedCardsPanel() {
setError(res.error ?? 'Failed to load received cards')
}
} catch (e) {
setError((e as Error)?.message ?? 'Network error')
setError(toErrorMessage(e) || 'Failed to load received cards')
} finally {
setLoading(false)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
RELATIONSHIP_OPTIONS,
type SuggestedPersonaView,
} from '../../../api/clients/fingerprintsClient'
import { toErrorMessage } from '../../../utils/schemaUtils'

/**
* localStorage key used to persist the set of dismissed suggestion
Expand Down Expand Up @@ -78,7 +79,7 @@ export default function SuggestedPersonasPanel() {
setError(res.error ?? 'Failed to load suggestions')
}
} catch (e) {
setError((e as Error)?.message ?? 'Network error')
setError(toErrorMessage(e) || 'Failed to load suggestions')
} finally {
setLoading(false)
}
Expand Down
Loading
Loading