{"record":{"id":"dfd87e7d7f6d8d4e","repo":"CherryHQ/cherry-studio","slug":"0","errorCode":"0","errorMessage":"DashScope async submit returned no task_id","messagePattern":"DashScope async submit returned no task_id","errorType":"exception","errorClass":"DashScopeApiError","httpStatus":null,"severity":"error","filePath":"src/main/ai/provider/custom/dashscope/dashscopeTransport.ts","lineNumber":399,"sourceCode":"      throw new Error(`Missing modelDescriptor for DashScope model: ${input.modelId}`)\n    }\n\n    const body = buildRequestBody(input, descriptor)\n    const extraHeaders: Record<string, string> = descriptor.isSync ? {} : { 'X-DashScope-Async': 'enable' }\n\n    const response = await this.request<DashScopeTaskResult>(descriptor.endpoint, 'POST', body, {\n      timeout: 120000,\n      signal: input.signal,\n      extraHeaders\n    })\n\n    if (descriptor.isSync) {\n      return { imageUrls: extractImageUrls(response.output, responseFamilyFor(descriptor)) }\n    }\n\n    const taskId = response.output.task_id\n    if (!taskId) {\n      throw new DashScopeApiError('DashScope async submit returned no task_id', 0)\n    }\n    this.pendingDescriptors.set(taskId, descriptor)\n    return { taskId }\n  }\n\n  async poll(\n    taskId: string,\n    options: {\n      signal?: AbortSignal\n      onProgress?: (progress: number) => void\n      modelDescriptor?: ImageTransportDescriptor\n    }\n  ): Promise<string[]> {\n    // On a cross-restart resume the in-memory descriptor is gone (the transport is\n    // rebuilt without the submit-time `pendingDescriptors` entry); fall back to the\n    // descriptor persisted in the job input so the response family is still\n    // resolved correctly instead of defaulting to `results`.\n    const descriptor = this.pendingDescriptors.get(taskId) ?? options.modelDescriptor","sourceCodeStart":381,"sourceCodeEnd":417,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/provider/custom/dashscope/dashscopeTransport.ts#L381-L417","documentation":"Thrown as a `DashScopeApiError` (statusCode `0`, meaning not a real HTTP failure) when an async submit returns HTTP 2xx but `response.output.task_id` is missing. A well-formed async DashScope submit must return a task id to poll; its absence means the response shape does not match the async contract — likely a routing mismatch (a sync model treated as async) or an undocumented API change.","triggerScenarios":"The descriptor's `isSync` flag is false but the endpoint actually returns synchronously (no task_id); DashScope changed its async response envelope; the wrong endpoint path was used for the model family.","commonSituations":"A model family was misclassified as async in the registry's `vendorTransport`; DashScope deprecated an endpoint and returns a different body; a sync model's descriptor `isSync` was left unset.","solutions":["Verify the model's `isSync` flag in the registry matches its actual response behavior — sync models return images directly, not a task id.","Log the raw submit response body to confirm the envelope shape, then align the descriptor's endpoint/isSync.","If DashScope changed the envelope, update the `DashScopeTaskOutput.task_id` extraction path."],"exampleFix":"// before — descriptor marked async for a sync model\n{ id: 'z-image-turbo', endpoint: '/api/v1/services/aigc/multimodal-generation/generation' /* isSync missing */ }\n// after\n{ id: 'z-image-turbo', endpoint: '/api/v1/services/aigc/multimodal-generation/generation', isSync: true }","handlingStrategy":"try-catch","validationCode":"const response = await transport.submit(input)\nif (!descriptor.isSync && !response.taskId) {\n  throw new Error(`Expected task_id from ${descriptor.endpoint} but got none — verify isSync routing`)\n}","typeGuard":null,"tryCatchPattern":"try {\n  const { taskId } = await transport.submit(input)\n} catch (e) {\n  if (e instanceof DashScopeApiError && e.statusCode === 0 && /no task_id/.test(e.message)) {\n    // routing mismatch — re-check descriptor.isSync / endpoint\n  }\n  throw e\n}","preventionTips":["Keep the registry's isSync flag aligned with each model family's real response shape","Log the raw submit response when integrating a new model family","Add an integration test asserting async submits return a task_id"],"tags":["api","dashscope","async","response-shape","routing"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}