marmelab/react-admin · error · Error

refetch is not available for a ListContext built from useLis

Error message

refetch is not available for a ListContext built from useList based on local data

What it means

When a ListContext is created from local data via useList (no dataProvider), there is no server query to re-run, so refetch is intentionally a stub that throws. Calling it on such a context is an API misuse.

Source

Thrown at packages/ra-core/src/controller/list/useList.ts:16

import { useCallback, useEffect, useRef, useState } from 'react';
import get from 'lodash/get.js';
import isEqual from 'lodash/isEqual.js';

import { removeEmpty } from '../../util';
import { Exporter, FilterPayload, RaRecord, SortPayload } from '../../types';
import { useResourceContext } from '../../core';
import usePaginationState from '../usePaginationState';
import useSortState from '../useSortState';
import { useRecordSelection } from './useRecordSelection';
import { GetDataOptions, ListControllerResult } from './useListController';
import { flattenObject } from '../../dataProvider/fetch';
import { defaultExporter } from '../../export';

const refetch = () => {
    throw new Error(
        'refetch is not available for a ListContext built from useList based on local data'
    );
};

/**
 * Handle filtering, sorting and pagination on local data.
 *
 * Returns the data and callbacks expected by <ListContext>.
 *
 * @example
 * const data = [
 *     { id: 1, name: 'Arnold' },
 *     { id: 2, name: 'Sylvester' },
 *     { id: 3, name: 'Jean-Claude' },
 * ]
 *
 * const MyComponent = () => {
 *     const listContext = useList({ data });

View on GitHub (pinned to 051f511bb0)

Solutions

  1. Don't call refetch on local-data lists; re-render by updating the source data state
  2. Conditionally render a refresh button only when the list is backed by a dataProvider
  3. Switch to a dataProvider-backed List/useListController if server refresh is needed
  4. Use a custom refresh handler that resets your local data instead of refetch

Example fix

// before
const { refetch } = useListContext();
<Button onClick={() => refetch()} /> // throws on local data
// after
const listContext = useListContext();
{listContext.data && <Button onClick={() => setLocalData(freshData)} />}
// or check availability: typeof refetch === 'function'
Defensive patterns

Strategy: type-guard

Validate before calling

const listContext = useListContext();
const canRefetch = typeof listContext.refetch === 'function' && !isLocalDataList;
if (canRefetch) listContext.refetch();

Type guard

const refetchIsAvailable = (ctx: ListControllerResult): ctx is ListControllerResult & { refetch: () => void } =>
  typeof ctx.refetch === 'function';

Try / catch

try { refetch(); } catch (e) { if (String(e).includes('local data')) { /* refresh local state instead */ } }

Prevention

When it happens

Trigger: Calling listContext.refetch() from useListContext when the list was built with <ListContextProvider value={useList({ data: localArray })}> or <ArrayField>-based contexts.

Common situations: Custom list views over local arrays; testing components with mock local data then reusing the same component against context.refetch; adding a refresh button to a local-data list.

Related errors


AI-assisted analysis of marmelab/react-admin@051f511bb0 (2026-08-30). Data as JSON: /api/errors/eacb5a7d7443b444. Report an issue: GitHub.