Skip to content
Braith.

CSV download returns HTML instead of a file.

Open the response body before changing your CSV code. A file named report.csv can contain a sign-in page, a proxy error or your app’s HTML shell.

Inspect the final response.

In the Network panel, locate the download request. Check its final URL, status, Content-Type and response body. A redirect to a login page can end with a successful HTML response.

If the response begins with an HTML doctype or a sign-in form, the export generator may never have handled the request. Inspect authentication, rewrites and the path sent by the download button.

Use the HAR viewer to inspect a saved recording. Do not share the original recording until you have reviewed it for secrets.

Reject an unexpected representation.

Check status and the expected media type before offering a file. The check below catches HTML, but it cannot establish that the CSV contains the right rows.

const response = await fetch("/api/reports/export");
const type = response.headers.get("content-type") || "";
if (!response.ok || !/^text\/csv(?:;|$)/i.test(type)) {
  throw new Error("The server did not return a CSV report");
}
const csv = await response.text();
// Validate the export contract before creating the download.

Use your actual documented media type if the endpoint intentionally returns another format. Do not turn a failed response into a downloadable file just because its body exists.

Check the download headers.

Set the correct Content-Type on the file response. Content-Disposition can suggest attachment delivery and a filename; it does not convert HTML into CSV. Inspect it with the Content-Disposition parser.

For a browser cross-origin fetch, exposing the filename header may need Access-Control-Expose-Headers. A navigation download and a scripted fetch are different request contexts.

Test signed-in and expired sessions.

Exercise a valid user, a signed-out user and an expired session. The authorised request should return a usable report. An API denial should produce an explicit error rather than a 200 login page with a CSV filename. Check file structure with the CSV validator, then compare expected records.

References: Content-Disposition and Fetch response handling.

Keep checking after the fix.

Braith reviews sampled customer activity for likely problems, including flows you have not defined. Core outcome checks add context where you need it.

Connect with Pro · £59/monthTry Free

Connect first. Pay only when you explicitly activate a paid plan.