CherryHQ/cherry-studio · error · Error

ModelScope API request timeout after ${timeout / 1000}s

Error message

ModelScope API request timeout after ${timeout / 1000}s

What it means

Thrown when the internal AbortController (set by setTimeout for `timeout` ms) fires before the ModelScope fetch resolves, AND the abort did NOT originate from the caller's external signal. It is distinct from the externally-aborted path, which throws a synthesized AbortError instead. The message reports the configured timeout in seconds for diagnostics.

Source

Thrown at src/main/ai/provider/custom/modelscope/modelscopeTransport.ts:236

        ...options.extraHeaders
      },
      signal: controller.signal
    }
    if (method === 'POST' && body !== undefined) {
      fetchOptions.body = JSON.stringify(body)
    }

    try {
      const response = await fetch(`${this.baseURL}${path}`, fetchOptions)
      if (!response.ok) {
        const errorText = (await response.text().catch(() => '')).slice(0, 500)
        throw new ModelscopeApiError(`ModelScope API error: ${response.status} - ${errorText}`, response.status)
      }
      return (await response.json()) as T
    } catch (error) {
      if (error instanceof Error && error.name === 'AbortError') {
        if (externallyAborted) throw createAbortError('ModelScope API request aborted')
        throw new Error(`ModelScope API request timeout after ${timeout / 1000}s`)
      }
      throw error
    } finally {
      clearTimeout(timeoutId)
      externalSignal?.removeEventListener('abort', onExternalAbort)
    }
  }
}

export function createModelscopeTransport(settings: ModelscopeTransportSettings): ModelscopeTransport {
  return new ModelscopeTransport(settings)
}

export type { ModelscopeTransport }

View on GitHub (pinned to 726446b54c)

Solutions

  1. Retry once with backoff — timeouts are frequently transient (network blip / cold load).
  2. If submit consistently times out, raise the per-call timeout (submit uses 120000ms; pass a larger options.timeout for known-slow cold-start models).
  3. Verify network/proxy reachability to api-inference.modelscope.cn; check whether a corporate proxy is silently dropping long-lived POSTs.
  4. Confirm the user is not on a metered/offline connection.

Example fix

// before
const r = await this.request(path, 'POST', body, { timeout: 120000 })
// after — escalate timeout for known slow cold-start models
const r = await this.request(path, 'POST', body, { timeout: coldStartModel ? 300000 : 120000 })
Defensive patterns

Strategy: retry

Validate before calling

// No request-time validation prevents a timeout; budget it
const timeout = coldStartModel ? 300000 : DEFAULT_TIMEOUT

Type guard

export function isModelscopeTimeoutError(e: unknown): boolean {
  return e instanceof Error && /^ModelScope API request timeout after/.test(e.message)
}

Try / catch

try {
  await transport.submit(input)
} catch (e) {
  if (isModelscopeTimeoutError(e)) {
    await backoffRetry(() => transport.submit(input), { maxAttempts: 2 })
  }
  throw e
}

Prevention

When it happens

Trigger: request() is called with a `timeout` (DEFAULT_TIMEOUT for poll, 120000ms for submit, 10000ms for task polls) and the fetch neither resolves nor is externally aborted within that window. Happens during vendor slowness, model cold-load, DNS stalls, or a hung TCP connection behind a proxy.

Common situations: Cold-loading a large diffusion model on the ModelScope side exceeding the submit timeout, network throttling, corporate proxy buffering, or the user is on a slow link and 120s submit budget is too tight.

Understand the failure class

Related errors


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/bf715cfd04c3cd1f. Report an issue: GitHub.