Skip to content

Ошибки

Библиотека нормализует Axios errors для UI и lifecycle callbacks, но не скрывает исходную ошибку при throw.

Нормализация

ts
import { normalizeAxiosError } from "@dubium/query-layer/axios"

try {
  await users.refetch()
} catch (cause) {
  const error = normalizeAxiosError(cause)

  console.log({
    code: error.code,
    message: error.message,
    status: error.status,
    isAxiosError: error.isAxiosError,
  })
}

UI должен опираться на нормализованные поля, а не на внутреннюю структуру AxiosError.

Классификация

ts
import {
  isForbiddenError,
  isServerError,
  isUnauthorizedError,
} from "@dubium/query-layer/axios"

if (isUnauthorizedError(error)) redirectToLogin()
else if (isForbiddenError(error)) showAccessDenied()
else if (isServerError(error)) showTemporaryFailure()

Состояние ошибки в store

ts
if (users.isError) {
  const status = users.error?.status
  if (status === 404) showEmptyState()
  else showRetryButton(() => users.refetch())
}

При ошибке background refetch старые данные могут оставаться в data. Не заменяйте весь экран spinner/error, если hasData === true.

Политика повторов

ts
const store = createQueryStore({
  queryKey: () => ["profile"],
  queryFn: loadProfile,
  retry: (failureCount, error) => {
    const normalized = normalizeAxiosError(error)
    if (normalized.status && normalized.status < 500) return false
    return failureCount < 2
  },
  retryDelay: (failureCount) => Math.min(500 * 2 ** failureCount, 5_000),
})

Не повторяйте небезопасную mutation автоматически без серверной идемпотентности.

Отмена

Cancellation — отдельный исход, а не пользовательская ошибка. Не показывайте toast при закрытии экрана.

ts
try {
  await store.fetch()
} catch (error) {
  if (error instanceof DOMException && error.name === "AbortError") return
  throw error
}

Axios также может вернуть CanceledError; внутренний lifecycle распознаёт оба варианта.

Timeout конкретного RequestStore-вызова

ts
const health = createRequestStore({
  api: healthApi,
})

try {
  // timeout — AxiosRequestConfig, а не поле RequestStore options.
  await health.executeWithConfig([], { timeout: 3_000 })
} catch (error) {
  if (health.error?.message.includes("timeout")) {
    showMessage("Сервис отвечает слишком долго")
  }
}

Ошибки persistence

ts
const persistence = await persistQueryRuntime({
  runtime,
  persister,
  onPersistError: (error) => {
    logger.warn("cache persistence unavailable", { error })
  },
})

Cache persistence обычно деградирует мягко. Ошибка сохранения offline-команды, наоборот, может требовать блокировки пользовательского действия.

Ошибки orchestration

ts
import {
  WorkflowExecutionError,
} from "@dubium/query-layer/orchestration"

try {
  await workflow.execute()
} catch (error) {
  if (error instanceof WorkflowExecutionError) {
    console.log(error.failedNodeId, error.cause, error.compensationErrors)
  }
}

Сохраняйте в telemetry безопасные идентификаторы, но не request body, токены или persisted snapshots.