agalwood/Motrix · error · HttpError

plugin.http.timeout

plugin.http.timeout

Error message

Request timed out after ${timeoutMs}ms

What it means

A setTimeout timer fires after timeoutMs (clamped to between 1_000ms and 300_000ms) and aborts the internal controller with reason 'timeout'. The undici request rejects, the catch block matches the reason, and the timeout is surfaced as a typed HttpError rather than a generic AbortError. timeoutMs comes from opts.timeoutMs or the host default.

Source

Thrown at src/core/plugin/capabilities/http.ts:334

            // different host.
            delete reqHeaders.cookie
          }
        }

        let response: Awaited<ReturnType<typeof undiciRequest>>
        try {
          response = await undiciRequest(currentUrl, {
            method,
            headers: reqHeaders,
            body: bodyPayload,
            signal: internalCtrl.signal,
            dispatcher,
          })
        } catch (err: unknown) {
          if (internalCtrl.signal.aborted) {
            const reason = internalCtrl.signal.reason
            if (reason === 'timeout') {
              throw new HttpError(
                'plugin.http.timeout',
                `Request timed out after ${timeoutMs}ms`
              )
            }
            if (reason === 'plugin_abort') {
              throw new HttpError(
                'plugin.http.aborted',
                'Request aborted by plugin'
              )
            }
            throw new HttpError('plugin.http.aborted', 'Request aborted')
          }
          if (
            err instanceof Error &&
            (err.name === 'AbortError' ||
              err.name === 'DOMException' ||
              err.constructor?.name === 'DOMException')
          ) {

View on GitHub (pinned to 1a708ee577)

Solutions

  1. Raise opts.timeoutMs up to the 300_000ms clamp ceiling where the endpoint legitimately needs it.
  2. Move large transfers to a background job and poll, instead of blocking one HTTP call.
  3. Retry with exponential backoff for transient slowness.
  4. Optimize the server endpoint's p99 latency.

Example fix

// before
await http.request({ url, responseType: 'json', timeoutMs: 1000 })

// after
await http.request({ url, responseType: 'json', timeoutMs: 30000 })
Defensive patterns

Strategy: retry

Validate before calling

const timeoutMs = Math.min(300_000, Math.max(1_000, expectedLatencyMs * 3))
await http.request({ url, responseType: 'json', timeoutMs })

Try / catch

for (const attempt of [1,2,3]) {
  try {
    return await http.request({ url, responseType: 'json', timeoutMs })
  } catch (e) {
    if (e instanceof HttpError && e.code === 'plugin.http.timeout' && attempt < 3) {
      await sleep(2 ** attempt * 200); continue
    }
    throw e
  }
}

Prevention

When it happens

Trigger: Server response slower than timeoutMs; timeoutMs explicitly set too low; network stall mid-stream; large upload that cannot finish in the window.

Common situations: Default timeout too aggressive for slow endpoints; plugin does not override opts.timeoutMs and inherits a small host default; cold-start latency on a serverless target.

Understand the failure class

Related errors


AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12). Data as JSON: /api/errors/94373e95bc8d9acc. Report an issue: GitHub.