agalwood/Motrix · error · HttpError

plugin.http.response_type_required

plugin.http.response_type_required

Error message

responseType is required (text | json | bytes)

What it means

request() deliberately does not default responseType. The caller must declare one of 'text' | 'json' | 'bytes' so the response body is parsed and typed unambiguously. Omitting it throws before any URL parsing or network work occurs.

Solutions

  1. Always set opts.responseType to 'text', 'json', or 'bytes' on every request() call.
  2. If using http.get/http.post convenience helpers, confirm they forward responseType.
  3. Make the options object's type HttpRequestOptions<'json'> (or similar) so the compiler rejects omission.

Example fix

// before
await http.request({ url: 'https://api.example.com', method: 'GET' })

// after
await http.request({ url: 'https://api.example.com', method: 'GET', responseType: 'json' })
Defensive patterns

Strategy: type-guard

Validate before calling

const RESPONSE_TYPES = ['text', 'json', 'bytes'] as const
if (!RESPONSE_TYPES.includes(opts.responseType)) {
  throw new Error('responseType must be set')
}

Type guard

type ResponseType = 'text' | 'json' | 'bytes'
function hasResponseType<R extends ResponseType>(
  o: { responseType?: R }
): o is { responseType: R } {
  return o.responseType === 'text' || o.responseType === 'json' || o.responseType === 'bytes'
}

Prevention

When it happens

Trigger: Calling http.request({ url, method }) with no responseType; copy-pasting a fetch()-style call into this API assuming a default Response object; passing a partially-built options object whose responseType was conditionally set and ended up undefined.

Common situations: Migration from fetch/axios which return raw responses; TypeScript bypassed via `any`; refactor that hoisted options construction away from the call site.

Related errors


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

Appendix: source

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

  private readonly defaultTimeoutMs: number
  private readonly defaultMaxBodyBytes: number

  constructor(opts?: HttpCapabilityHostOptions) {
    this.cookieJar = opts?.cookieJar
    this.defaultTimeoutMs = opts?.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS
    this.defaultMaxBodyBytes =
      opts?.defaultMaxBodyBytes ?? DEFAULT_MAX_BODY_BYTES
  }

  // -------------------------------------------------------------------------
  // request
  // -------------------------------------------------------------------------

  async request<R extends HttpResponseType>(
    opts: HttpRequestOptions<R>
  ): Promise<HttpResponse<R>> {
    if (opts.responseType === undefined) {
      throw new HttpError(
        'plugin.http.response_type_required',
        'responseType is required (text | json | bytes)'
      )
    }

    const parsed = parseUrl(opts.url)
    checkScheme(parsed)

    const timeoutMs = clampTimeout(opts.timeoutMs, this.defaultTimeoutMs)
    const maxBodyBytes = clampMaxBody(
      opts.maxBodyBytes,
      this.defaultMaxBodyBytes
    )
    const method = (opts.method ?? 'GET').toUpperCase() as Dispatcher.HttpMethod
    const redirect = opts.redirect ?? 'follow'
    const useCookies = opts.cookies === 'jar'
    const dispatcher = pickDispatcher(opts.proxy)

View on GitHub (pinned to 1a708ee577)