CherryHQ/cherry-studio · error · Error
${provider} returned a task id but does not implement pollin
Error message
${provider} returned a task id but does not implement polling What it means
Thrown by the shared `createImageGenerationModel` adapter when `transport.submit()` returns a `taskId` but `transport.poll` is undefined. The submit→poll contract requires that any transport returning a task id also implement polling; otherwise the generated images can never be retrieved. This is a transport implementation contract violation.
Source
Thrown at src/main/ai/provider/custom/imageGenerationModel.ts:118
const submitResult = await transport.submit({
modelId,
prompt: options.prompt,
n: options.n,
size: options.size,
seed: options.seed,
files: options.files,
mask: options.mask,
providerParams,
signal: abortSignal
})
let urls: string[]
if (submitResult.imageUrls) {
urls = submitResult.imageUrls
} else if (submitResult.taskId) {
if (!transport.poll) {
throw new Error(`${provider} returned a task id but does not implement polling`)
}
let cancelRequested = false
const cancelRemoteTask = () => {
if (cancelRequested) return
cancelRequested = true
void transport.cancel?.(submitResult.taskId as string).catch(() => {})
}
if (abortSignal?.aborted) {
cancelRemoteTask()
throw createAbortError('Image generation aborted')
}
abortSignal?.addEventListener('abort', cancelRemoteTask, { once: true })
try {
urls = await transport.poll(submitResult.taskId, { signal: abortSignal, onProgress })
} finally {View on GitHub (pinned to 726446b54c)
Solutions
- Implement `poll(taskId, options)` on the transport so task results can be retrieved.
- If the transport is genuinely single-shot, have `submit` return `{ imageUrls }` directly instead of a `taskId`.
- Add a compile-time check that any transport with async submit also declares poll.
Example fix
// before
const transport = {
async submit(input) {
const { taskId } = await api.create(input)
return { taskId } // poll missing
}
}
// after
const transport = {
async submit(input) {
const { taskId } = await api.create(input)
return { taskId }
},
async poll(taskId) {
const result = await api.get(taskId)
return result.images
}
} Defensive patterns
Strategy: type-guard
Validate before calling
if (!('poll' in transport) || typeof transport.poll !== 'function') {
throw new Error('Transport must implement poll() if submit() can return a taskId')
} Type guard
const transportCanPoll = (
t: ImageGenerationTransport
): t is ImageGenerationTransport & { poll: NonNullable<ImageGenerationTransport['poll']> } =>
typeof t.poll === 'function' Prevention
- Any transport returning a taskId must implement poll — make it a compile-time rule
- For single-shot transports, return { imageUrls } from submit instead
- Unit-test the submit/poll pairing on every new transport
When it happens
Trigger: A custom `ImageGenerationTransport` whose `submit` returns `{ taskId }` but omits the optional `poll` method. All built-in async transports (DashScope, ModelScope, DMXAPI) implement both.
Common situations: Writing a new transport and forgetting `poll`; refactoring a single-shot transport to return a task id without adding polling; a transport stub used in tests.
Related errors
- OpenAI-compatible reranking model only supports text documen
- Rerank response results must be objects
- Task polling timeout
- Rerank response must contain a results array
- Rerank response results must contain numeric index and relev
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/8e47f7a023d545ab.
Report an issue: GitHub.