{"record":{"id":"929ffd71c13812fe","repo":"marmelab/react-admin","slug":"the-x-total-count-header-is-missing-in-the-http-re","errorCode":null,"errorMessage":"The X-Total-Count header is missing in the HTTP Response. The jsonServer 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 X-Total-Count in the Access-Control-Expose-Headers header?","messagePattern":"The X-Total-Count header is missing in the HTTP Response\\. The jsonServer 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 X-Total-Count in the Access-Control-Expose-Headers header\\?","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/ra-data-json-server/src/index.ts","lineNumber":58,"sourceCode":"        const { field, order } = params.sort || {};\n        const query = {\n            ...fetchUtils.flattenObject(params.filter),\n            _sort: field,\n            _order: order,\n            _start:\n                page != null && perPage != null\n                    ? (page - 1) * perPage\n                    : undefined,\n            _end: page != null && perPage != null ? page * perPage : undefined,\n            _embed: params?.meta?.embed,\n        };\n        const url = `${apiUrl}/${resource}?${stringify(query)}`;\n\n        const { headers, json } = await httpClient(url, {\n            signal: params?.signal,\n        });\n        if (!headers.has('x-total-count')) {\n            throw new Error(\n                'The X-Total-Count header is missing in the HTTP Response. The jsonServer 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 X-Total-Count in the Access-Control-Expose-Headers header?'\n            );\n        }\n        const totalString = headers.get('x-total-count')!.split('/').pop();\n        if (totalString == null) {\n            throw new Error(\n                'The X-Total-Count header is invalid in the HTTP Response.'\n            );\n        }\n        return { data: json, total: parseInt(totalString, 10) };\n    },\n\n    getOne: async (resource, params) => {\n        let url = `${apiUrl}/${resource}/${params.id}`;\n        if (params?.meta?.embed) {\n            url += `?_embed=${params.meta.embed}`;\n        }\n        const { json } = await httpClient(url, { signal: params?.signal });","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/marmelab/react-admin/blob/051f511bb0afb5ea565c2d3728bf4dab0a6fa5e0/packages/ra-data-json-server/src/index.ts#L40-L76","documentation":"The jsonServer data provider reads the total record count for paginated lists from the X-Total-Count response header. If the header is absent on a list response, pagination cannot be computed and the provider throws with guidance about CORS exposure.","triggerScenarios":"Any getList call whose HTTP response lacks the x-total-count header — typically because the API doesn't send it, or because CORS filters it out unless listed in Access-Control-Expose-Headers.","commonSituations":"Pointing the provider at a non-json-server API that doesn't emit the header; CORS-blocking the header in browsers while present in curl; custom middleware stripping headers; using json-server without the count header on custom routes.","solutions":["Make the API send X-Total-Count on list endpoints (e.g. res.set('X-Total-Count', total) in Express).","If using CORS, add it to Access-Control-Expose-Headers: 'X-Total-Count' on the server.","Verify with curl -I that the header is actually present in the raw response.","Test outside the browser to distinguish missing header from CORS filtering."],"exampleFix":"// before (Express + CORS)\napp.use(cors()); // header hidden from browser\n// after\napp.use(cors({ exposedHeaders: ['X-Total-Count'] }));\nres.set('X-Total-Count', total);","handlingStrategy":"try-catch","validationCode":"const res = await fetch(`${apiUrl}/${resource}?range=0-9`);\nif (!res.headers.has('x-total-count')) {\n  throw new Error('Backend does not expose X-Total-Count on list endpoints');\n}","typeGuard":"const hasTotalCount = (headers: Headers): boolean => headers.has('x-total-count');","tryCatchPattern":"try {\n  const { data, total } = await dataProvider.getList(resource, params);\n  return { data, total };\n} catch (e) {\n  if (e.message.includes('X-Total-Count')) {\n    console.error('List response missing X-Total-Count; check API and CORS expose-headers', e);\n  }\n  throw e;\n}","preventionTips":["Configure the API (or json-server middleware) to always send X-Total-Count on collections.","Add 'X-Total-Count' to Access-Control-Expose-Headers in your CORS setup.","Verify headers with curl before debugging in the browser, to rule out CORS filtering.","Add an integration test asserting the header on list endpoints."],"tags":["http","headers","pagination","cors","ra-data-json-server"],"backgroundTag":"missing-response-header","analyzedSha":"051f511bb0afb5ea565c2d3728bf4dab0a6fa5e0","analyzedAt":"2026-08-30T02:28:14.926Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}