QuantumNous/new-api · error · Error

Failed to fetch usage

Error message

Failed to fetch usage

What it means

Thrown by handleQueryCodexUsage in the balance-query dialog when the Codex usage lookup fails. It calls getCodexUsage(row.id); if the response has success=false or the fetch rejects, the backend message (or this i18n fallback) is toasted. The dialog only shows this action for channels with type === 57.

Source

Thrown at web/src/features/channels/components/dialogs/balance-query-dialog.tsx:68

  const queryClient = useQueryClient()
  const [isQuerying, setIsQuerying] = useState(false)
  const [balance, setBalance] = useState<number | null>(null)
  const [balanceUpdatedTime, setBalanceUpdatedTime] = useState<number | null>(
    null
  )
  const [codexUsageResponse, setCodexUsageResponse] =
    useState<CodexUsageDialogData | null>(null)

  const isCodex = currentRow?.type === 57

  const handleQueryCodexUsage = async () => {
    const row = currentRow
    if (!row) return
    setIsQuerying(true)
    try {
      const res = await getCodexUsage(row.id)
      if (!res.success) {
        throw new Error(res.message || t('Failed to fetch usage'))
      }
      setCodexUsageResponse(res)
    } catch (error: unknown) {
      toast.error(
        error instanceof Error ? error.message : t('Failed to fetch usage')
      )
    } finally {
      setIsQuerying(false)
    }
  }

  useEffect(() => {
    if (!isCodex) return
    if (!open) return
    handleQueryCodexUsage()
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open, isCodex])

View on GitHub (pinned to e2c7aa7b10)

Solutions

  1. Verify the channel still exists and its key is current (re-save the key, then retry the dialog)
  2. Call the codex usage API for row.id directly and inspect the JSON message — it is shown instead of the fallback when present
  3. Check backend logs for the proxied upstream request failing (401/403/timeout from Codex)
  4. Confirm your admin session is still valid (refresh the page; re-login if 401)

Example fix

// before
const res = await getCodexUsage(row.id)
if (!res.success) {
  throw new Error(res.message || t('Failed to fetch usage'))
}
// after - distinguish empty data from failure
const res = await getCodexUsage(row.id)
if (!res.success) {
  throw new Error(res.message || t('Failed to fetch usage'))
}
if (!res.data) {
  toast.warning(t('No usage data returned for this channel'))
  return
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!row || row.type !== 57) return // dialog action is Codex-only

Type guard

const isCodexRow = (row: ChannelRow | null | undefined): row is ChannelRow =>
  !!row && row.type === 57 && typeof row.id === 'number'

Try / catch

try {
  const res = await getCodexUsage(row.id)
  if (!res.success) throw new Error(res.message || t('Failed to fetch usage'))
  setCodexUsageResponse(res)
} catch (error: unknown) {
  toast.error(error instanceof Error ? error.message : t('Failed to fetch usage'))
} finally {
  setIsQuerying(false)
}

Prevention

When it happens

Trigger: Opening Balance Query on a type-57 (Codex) channel and triggering the query while getCodexUsage returns success=false or throws — invalid credential, upstream Codex API error, deleted channel id, or expired admin session.

Common situations: Codex channel credential expired or revoked upstream; the channel was deleted in another tab so row.id no longer exists; backend has no route/permission for the requesting user role; network interruption between browser and gateway.

Related errors


AI-assisted analysis of QuantumNous/new-api@e2c7aa7b10 (2026-08-15). Data as JSON: /api/errors/d0718eb58945fa8c. Report an issue: GitHub.