import { isHttpError } from '@immich/sdk'; import { toastManager } from '@immich/ui'; export function getServerErrorMessage(error: unknown) { if (!isHttpError(error)) { return; } // errors for endpoints without return types aren't parsed as json let data = error.data; if (typeof data === 'string') { try { data = JSON.parse(data); } catch { // Not a JSON string } } if (Array.isArray(data?.errors) && data.errors.length > 0) { const details = data.errors .map(({ path, message }) => { const field = path .map((segment, i) => (typeof segment === 'number' ? `[${segment}]` : i === 0 ? segment : `.${segment}`)) .join(''); return field ? `${field}: ${message}` : message; }) .join(', '); return `${data.message}: ${details}`; } return data?.message || error.message; } export function standardizeError(error: unknown) { return error instanceof Error ? error : new Error(String(error)); } export function handleError(error: unknown, localizedMessage: string, options?: { notify?: boolean }) { const { notify = true } = options ?? {}; const standardizedError = standardizeError(error); if (standardizedError.name === 'AbortError') { return; } console.error(`[handleError]: ${standardizedError}`, error, standardizedError.stack); try { let serverMessage = getServerErrorMessage(error); if (serverMessage) { serverMessage = `${serverMessage.slice(0, 75)}\n(Immich Server Error)`; } const errorMessage = serverMessage || localizedMessage; if (notify) { toastManager.danger(errorMessage); } return errorMessage; } catch (error) { console.error(error); return localizedMessage; } } export async function handleErrorAsync(fn: () => Promise, localizedMessage: string): Promise { try { return await fn(); } catch (error: unknown) { handleError(error, localizedMessage); return; } }