Crosstalk-Solutions/project-nomad · error
Failed to fetch remote ZIM files.
Error message
Failed to fetch remote ZIM files.
What it means
Thrown inside a React Query infinite-query pageFetchParam callback when api.listRemoteZimFiles({start, count, query}) resolves falsy. The Kiwix remote catalog request failed or returned an empty/unparseable body while paginating the remote ZIM explorer.
Source
Thrown at admin/inertia/pages/settings/zim/remote-explorer.tsx:153
} = useQuery<BrowseResult>({
queryKey: ['browse-library', browseUrl],
queryFn: () => api.browseLibrary(browseUrl!) as Promise<BrowseResult>,
enabled: !!browseUrl && selectedSource !== 'default',
refetchOnWindowFocus: false,
retry: false,
})
const { data, fetchNextPage, isFetching, isLoading } =
useInfiniteQuery<ListRemoteZimFilesResponse>({
queryKey: ['remote-zim-files', query],
queryFn: async ({ pageParam = 0 }) => {
// pageParam is an opaque Kiwix offset returned by the backend as `next_start`.
// The backend accumulates across multiple upstream pages when needed (#731), so the
// frontend can't derive the next offset from a 12-item page assumption.
const start = typeof pageParam === 'number' ? pageParam : 0
const res = await api.listRemoteZimFiles({ start, count: 12, query: query || undefined })
if (!res) {
throw new Error('Failed to fetch remote ZIM files.')
}
return res.data
},
initialPageParam: 0,
getNextPageParam: (lastPage) => (lastPage.has_more ? lastPage.next_start : undefined),
refetchOnWindowFocus: false,
placeholderData: keepPreviousData,
enabled: selectedSource === 'default',
})
const flatData = useMemo(() => {
const mapped = data?.pages.flatMap((page) => page.items) || []
const localNames = new Set(localFiles?.map((f) => f.name) ?? [])
return mapped.filter((item) => {
const isDownloading = downloads?.some((download) => {
const filename = item.download_url.split('/').pop()
return filename && download.filepath.endsWith(filename)
})View on GitHub (pinned to 0bd1c6f4f9)
Solutions
- Test the backend ZIM catalog proxy endpoint directly with the same start/count to see the raw upstream status
- Verify internet connectivity/egress rules from the appliance to the Kiwix library
- Add rate-limit/backoff on the infinite scroll and rely on React Query retry rather than throwing on first falsy response
- If upstream schema changed, update the backend mapper to keep returning {data, has_more, next_start}
Example fix
// before
const res = await api.listRemoteZimFiles({ start, count: 12, query: query || undefined })
if (!res) {
throw new Error('Failed to fetch remote ZIM files.')
}
return res.data
// after
const res = await api.listRemoteZimFiles({ start, count: 12, query: query || undefined })
if (!res) {
throw new Error(`Failed to fetch remote ZIM files (offset ${start}).`)
}
return res.data Defensive patterns
Strategy: retry
Validate before calling
if (!(await navigator.onLine)) throw new Error('Offline — remote ZIM catalog unavailable') Type guard
const isZimPage = (r: unknown): r is { data: ZimFile[]; has_more: boolean; next_start?: number } =>
Array.isArray((r as any)?.data) Try / catch
pageFn: async ({ pageParam }) => {
try {
const res = await api.listRemoteZimFiles({ start: pageParam ?? 0, count: 12, query: query || undefined })
if (!res) throw new Error('Failed to fetch remote ZIM files.')
return res.data
} catch (e) {
queryClient.invalidateQueries({ queryKey: ['remote-zim'] })
throw e
}
} Prevention
- Rely on React Query's retry/backoff for transient upstream failures
- Show offline state in the remote explorer UI before fetching
- Throttle infinite scroll to avoid hammering the Kiwix catalog
When it happens
Trigger: Fetching page 2+ of the Kiwix library catalog with an opaque next_start offset when the upstream Kiwix server is unreachable, rate-limits the appliance, or the backend proxy returns an error body without throwing.
Common situations: Appliance offline or with restricted egress to library.kiwix.org, upstream Kiwix API schema change breaking the backend mapper, rate limiting after rapid infinite-scroll paging.
Related errors
- No internet — connect to download FDA drug data. (${msg})
- Upload failed
- Maximum of 10 custom libraries allowed
- Custom library not found
- ${error.message}
AI-assisted analysis of Crosstalk-Solutions/project-nomad@0bd1c6f4f9 (2026-08-27).
Data as JSON: /api/errors/ac8eaa23ca122bd2.
Report an issue: GitHub.