CherryHQ/cherry-studio · error · Error
PPIO API request timeout after ${timeout / 1000}s
Error message
PPIO API request timeout after ${timeout / 1000}s What it means
Thrown when PpioTransport.request()'s internal timeout AbortController fires before the fetch resolves, and the abort did NOT come from the caller's external signal (the external-abort path throws a synthesized AbortError instead). Reports the configured timeout in seconds.
Source
Thrown at src/main/ai/provider/custom/ppio/ppioTransport.ts:170
}
try {
const response = await fetch(url, fetchOptions)
if (!response.ok) {
const errorText = (await response.text().catch(() => '')).slice(0, 500)
throw new PpioApiError(`PPIO API error: ${response.status} - ${errorText}`, response.status)
}
const data = await response.json()
return data as T
} catch (error) {
if (error instanceof Error && error.name === 'AbortError') {
if (externallyAborted) {
throw createAbortError('PPIO API request aborted')
}
throw new Error(`PPIO API request timeout after ${timeout / 1000}s`)
}
throw error
} finally {
clearTimeout(timeoutId)
externalSignal?.removeEventListener('abort', onExternalAbort)
}
}
async submit(input: ImageGenerationSubmitInput): Promise<{ taskId?: string; imageUrls?: string[] }> {
const bagParams = input.providerParams as PpioProviderParams
const descriptor = input.modelDescriptor
if (!descriptor) {
throw new Error(`Unknown model: ${input.modelId}`)
}
// Native AI SDK fields (size / seed) land on `input.*` post-canonicalGenerate
// partition, not in the providerOptions bag. Merge them into a unified
// view so the per-model builders below can read uniformly. `ppioSeed`View on GitHub (pinned to 726446b54c)
Solutions
- Retry once with backoff — most PPIO timeouts are transient.
- Raise options.timeout for submit (120000ms) if the vendor is known slow; raise poll timeout (10000ms) if getTaskResult consistently stalls.
- Verify network/proxy reachability to api.ppio.com; check for corporate proxies that drop long POSTs.
- Confirm the user is not on a degraded connection.
Example fix
// before
const r = await this.request(endpoint, body, 'POST', { timeout: 120000 })
// after — escalate for slow vendors
const r = await this.request(endpoint, body, 'POST', { timeout: slowVendor ? 300000 : 120000 }) Defensive patterns
Strategy: retry
Validate before calling
// No request-time validation prevents a timeout; budget it const timeout = slowVendor ? 300000 : DEFAULT_TIMEOUT
Type guard
export function isPpioTimeoutError(e: unknown): boolean {
return e instanceof Error && /^PPIO API request timeout after/.test(e.message)
} Try / catch
try {
await transport.submit(input)
} catch (e) {
if (isPpioTimeoutError(e)) await backoffRetry(() => transport.submit(input), { maxAttempts: 2 })
throw e
} Prevention
- Size the per-call timeout to the operation (submit needs more than poll).
- Retry once on timeout before surfacing.
- Provide a cancel affordance for long submits.
When it happens
Trigger: request() with a `timeout` (DEFAULT_TIMEOUT default, 120000ms for submit, 10000ms for poll getTaskResult) where fetch neither resolves nor is externally aborted in time. Happens during vendor slowness, cold model load, network stalls, or proxy buffering.
Common situations: Submit exceeding the 120s budget on a slow link, poll GET exceeding 10s during vendor overload, proxy dropping long-lived connections, or offline/metered network.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- ModelScope API request timeout after ${timeout / 1000}s
- PPIO API error: ${response.status} - ${errorText}
- Task polling timeout
- Rerank response results must contain numeric index and relev
- DashScope API request timeout after ${timeout / 1000}s
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/5c306a3243765505.
Report an issue: GitHub.