marmelab/react-admin · error

The ${countHeader} header is missing in the HTTP Response. T

Error message

The ${countHeader} header is missing in the HTTP Response. The simple REST data provider expects responses for lists of resources to contain this header with the total number of results to build the pagination. If you are using CORS, did you declare ${countHeader} in the Access-Control-Expose-Headers header?

What it means

The simple REST data provider's getList reads the total count of records from a response header (Content-Range by default, configurable via httpLink/countHeader). If the response lacks that header, pagination cannot be built, so it throws. This is almost always a server or CORS configuration issue, not a client bug.

Source

Thrown at packages/ra-data-simple-rest/src/index.ts:75

        };
        if (params.meta && params.meta.embed) {
            query.embed = JSON.stringify(params.meta.embed);
        }
        const url = `${apiUrl}/${resource}?${stringify(query)}`;
        const options =
            countHeader === 'Content-Range'
                ? {
                      // Chrome doesn't return `Content-Range` header if no `Range` is provided in the request.
                      headers: new Headers({
                          Range: `${resource}=${rangeStart}-${rangeEnd}`,
                      }),
                      signal: params?.signal,
                  }
                : { signal: params?.signal };

        return httpClient(url, options).then(({ headers, json }) => {
            if (!headers.has(countHeader)) {
                throw new Error(
                    `The ${countHeader} header is missing in the HTTP Response. The simple REST data provider expects responses for lists of resources to contain this header with the total number of results to build the pagination. If you are using CORS, did you declare ${countHeader} in the Access-Control-Expose-Headers header?`
                );
            }
            return {
                data: json,
                total:
                    countHeader === 'Content-Range'
                        ? parseInt(
                              headers.get('content-range')!.split('/').pop() ||
                                  '',
                              10
                          )
                        : parseInt(headers.get(countHeader.toLowerCase())!),
            };
        });
    },

    getOne: async (resource, params) => {

View on GitHub (pinned to 051f511bb0)

Solutions

  1. Make the server send the count header (e.g. Content-Range: posts 0-9/42) on list endpoints
  2. If the API is cross-origin, add the header to Access-Control-Expose-Headers in the server's CORS config
  3. If your API uses a different header name, configure it: simpleRestProvider(url, httpClient, 'X-Total-Count')

Example fix

// before (Express)
res.set('Content-Range', `posts ${start}-${end}/${total}`);
// after (also expose for CORS)
res.set('Content-Range', `posts ${start}-${end}/${total}`);
res.set('Access-Control-Expose-Headers', 'Content-Range');
Defensive patterns

Strategy: validation

Validate before calling

// Probe the endpoint before wiring the provider
const res = await fetch(`${apiUrl}/posts?range=${encodeURIComponent('[0,9]')}`);
if (!res.headers.has('Content-Range')) {
    console.warn('Server does not send Content-Range; configure countHeader or fix server/CORS');
}

Type guard

const hasCountHeader = (headers: Headers, name = 'Content-Range'): boolean =>
    headers.has(name);

Try / catch

try {
    const data = await dataProvider.getList('posts', { pagination: { page: 1, perPage: 10 } });
} catch (e) {
    if (e instanceof Error && e.message.includes('header is missing')) {
        notify('Server does not expose the total count header; fix server/CORS config', { type: 'error' });
        return { data: [], total: 0 };
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling dataProvider.getList() when the backend response for the collection endpoint does not include the count header (e.g. missing Content-Range), or the header is present server-side but stripped by the browser because it was not listed in Access-Control-Expose-Headers.

Common situations: Cross-origin APIs where the server sends Content-Range but does not expose it via CORS; backends (e.g. Express, Rails, API Platform misconfigured) that never send Content-Range for list endpoints; using a custom countHeader name (via httpLink customHeaderName option) that the server does not actually send.

Related errors


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