fix(ui): handle non-JSON error responses in form-fetch-action (#12635)

### Problem

When a user clicks the merge button on a pull request and their quota is exceeded, the UI displays ( cf screenshot ):

> Network error SyntaxError: Unexpected token 'Q', "Quota exceeded." is not valid JSON

### Fix

Read the response body as text first with `resp.text()`, then attempt `JSON.parse()`. If parsing succeeds, use the existing `errorMessage` logic. If it fails, display the raw text directly in the error toast.

This is the same approach already used by Dropzone for attachment uploads, where the `error` event handler passes the response body directly to `showErrorToast`. ( cf screenshot )

### Tests for JavaScript changes

The function is not exported, I cannot create a unit test. Do you want me to export all the logic in an exported function ?

### Release notes

- [X] This change will be noticed by a Forgejo user or admin (feature, bug fix, performance, etc.). I suggest to include a release note for this change.

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/12635
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
This commit is contained in:
steven.guiheux 2026-05-19 21:09:44 +02:00 committed by Mathieu Fenniak
parent cd5a1173d5
commit 6574dba902

View file

@ -94,13 +94,19 @@ async function fetchActionDoRequest(actionElem, url, opt) {
}
return;
} else if (resp.status >= 400 && resp.status < 500) {
const data = await resp.json();
// the code was quite messy, sometimes the backend uses "err", sometimes it uses "error", and even "user_error"
// but at the moment, as a new approach, we only use "errorMessage" here, backend can use JSONError() to respond.
if (data.errorMessage) {
showErrorToast(data.errorMessage, {useHtmlBody: data.renderFormat === 'html'});
} else {
showErrorToast(`server error: ${resp.status}`);
const text = await resp.text();
try {
const data = JSON.parse(text);
// the code was quite messy, sometimes the backend uses "err", sometimes it uses "error", and even "user_error"
// but at the moment, as a new approach, we only use "errorMessage" here, backend can use JSONError() to respond.
if (data.errorMessage) {
showErrorToast(data.errorMessage, {useHtmlBody: data.renderFormat === 'html'});
} else {
showErrorToast(`server error: ${resp.status}`);
}
} catch {
// if the response is not valid JSON (e.g. plain text "Quota exceeded."), show it directly
showErrorToast(text.trim() || `server error: ${resp.status}`);
}
} else {
showErrorToast(`server error: ${resp.status}`);