- Affected version
- 2.3.7
Any AJAX submission of a form with
with:
This affects post submissions with attached files, conversation messages with attachments, profile banner / avatar uploads,
attachment-manager edits — anything that hits the
itself (via flow.js → raw XHR) is not affected; what fails is the form save that runs after the chunks finish.
Root cause
The new fetch-based
The
But
it (around line 189):
…where
form, and
Reproduction
Easier repro for testing without throttling: temporarily add
Suggested fix
In
out:
(The cleanup path at the end of the function should already be a no-op for
but worth a glance.)
enctype="multipart/form-data" that takes longer than 60 seconds aborts client-sidewith:
"The server did not respond in time. Please try again."
This affects post submissions with attached files, conversation messages with attachments, profile banner / avatar uploads,
attachment-manager edits — anything that hits the
form-submit handler with a file input. The chunked attachment upload itself (via flow.js → raw XHR) is not affected; what fails is the form save that runs after the chunks finish.
Root cause
The new fetch-based
XF.ajax in js/xf/core.js (around line 1956) computes the abort timer like this:
JavaScript:
const defaultTimeout = method.toUpperCase() === 'GET'
? 30000
: 60000
const timeoutId = setTimeout(
() => controller.abort(new DOMException('_XF_TIMEOUT', 'AbortError')),
options.timeout || defaultTimeout
)
The
|| fallback treats options.timeout === 0 as falsy, so it falls through to the 60s default.But
0 has been the long-standing jQuery-era idiom for "no timeout", and XF's own js/xf/form.js still uses it (around line 189):
JavaScript:
const ajaxOptions = { skipDefault: true }
if (isUploadForm)
{
ajaxOptions.timeout = 0
}
…where
isUploadForm = form.getAttribute('enctype') == 'multipart/form-data'. So XF asks for "no timeout" on every upload form, and
XF.ajax silently caps it at 60s. Reproduction
- Open any forum post reply form, attach a file (any size).
- In DevTools → Network, throttle to "Slow 3G" (or simulate a slow upstream another way).
- Click Post Reply.
- After ~60s the request is aborted client-side and the alert appears, even though the server is still happily processing.
Easier repro for testing without throttling: temporarily add
sleep(70); at the top of XF\Pub\Controller\Thread::actionAddReply (or any other multipart-form action) and submit any reply with an attachment. Suggested fix
In
js/xf/core.js, honor timeout: 0 as "no timeout" — skip the abort timer when the caller explicitly opts out:
JavaScript:
const defaultTimeout = method.toUpperCase() === 'GET'
? 30000
: 60000
const effectiveTimeout = options.timeout ?? defaultTimeout
let timeoutId = null
if (effectiveTimeout > 0)
{
timeoutId = setTimeout(
() => controller.abort(new DOMException('_XF_TIMEOUT', 'AbortError')),
effectiveTimeout
)
}
(The cleanup path at the end of the function should already be a no-op for
null via clearTimeout(null), but worth a glance.)