{"record":{"id":"3f1bcf941b800afa","repo":"CherryHQ/cherry-studio","slug":"unknown-model-input-modelid","errorCode":null,"errorMessage":"Unknown model: ${input.modelId}","messagePattern":"Unknown model: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/provider/custom/ppio/ppioTransport.ts","lineNumber":183,"sourceCode":"      if (error instanceof Error && error.name === 'AbortError') {\n        if (externallyAborted) {\n          throw createAbortError('PPIO API request aborted')\n        }\n\n        throw new Error(`PPIO API request timeout after ${timeout / 1000}s`)\n      }\n      throw error\n    } finally {\n      clearTimeout(timeoutId)\n      externalSignal?.removeEventListener('abort', onExternalAbort)\n    }\n  }\n\n  async submit(input: ImageGenerationSubmitInput): Promise<{ taskId?: string; imageUrls?: string[] }> {\n    const bagParams = input.providerParams as PpioProviderParams\n    const descriptor = input.modelDescriptor\n    if (!descriptor) {\n      throw new Error(`Unknown model: ${input.modelId}`)\n    }\n\n    // Native AI SDK fields (size / seed) land on `input.*` post-canonicalGenerate\n    // partition, not in the providerOptions bag. Merge them into a unified\n    // view so the per-model builders below can read uniformly. `ppioSeed`\n    // remains PPIO's bespoke wire field name; if the bag carries one\n    // explicitly we keep it, otherwise fall back to `input.seed`.\n    const params: PpioProviderParams = {\n      ...bagParams,\n      size: bagParams.size ?? input.size,\n      ppioSeed: bagParams.ppioSeed ?? input.seed\n    }\n\n    const requestParams = this.buildRequestParams(input, params, descriptor)\n\n    if (descriptor.isSync) {\n      const result = await this.request<PpioSyncResult>(descriptor.endpoint, requestParams, 'POST', {\n        signal: input.signal","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/provider/custom/ppio/ppioTransport.ts#L165-L201","documentation":"Thrown at the top of PpioTransport.submit() when input.modelDescriptor is missing. The descriptor carries the per-model endpoint path and sync/async flag that buildRequestParams needs; without it the transport cannot construct a valid request. Indicates a registry/descriptor resolution gap rather than a network problem.","triggerScenarios":"submit() is invoked with an input whose modelId has no entry in the PPIO model descriptor map (the source that produces PpioModelDescriptor). Concrete causes: a new PPIO model was added to the catalog but its descriptor was not wired in, the modelId string drifted (typo, version suffix), or descriptor resolution silently returned undefined.","commonSituations":"User picks a newly-listed PPIO model before its descriptor is registered, model id case/spacing mismatch, descriptor registry out of sync with the model catalog.","solutions":["Confirm the modelId in input matches a registered PpioModelDescriptor (id, endpoint, isSync, mode).","If the model is genuinely new, add its descriptor to the registry before exposing it for selection.","Validate modelId against the descriptor map at the call site before invoking submit.","Surface a user-facing 'this PPIO model is not yet supported' message instead of the generic throw."],"exampleFix":"// before\nif (!descriptor) throw new Error(`Unknown model: ${input.modelId}`)\n// after — typed, attributable\nif (!descriptor) throw new Error(`PPIO model '${input.modelId}' has no registered descriptor; add it to the descriptor map`)","handlingStrategy":"validation","validationCode":"// Validate the modelId has a descriptor before submit\nconst descriptor = resolvePpioModelDescriptor(input.modelId)\nif (!descriptor) {\n  throw new Error(`PPIO model '${input.modelId}' has no registered descriptor`)\n}","typeGuard":"export function isUnknownPpioModelError(e: unknown): boolean {\n  return e instanceof Error && /^Unknown model:/.test(e.message)\n}","tryCatchPattern":"try {\n  await transport.submit(input)\n} catch (e) {\n  if (isUnknownPpioModelError(e)) {\n    // surface 'model not yet supported' to the user\n  }\n  throw e\n}","preventionTips":["Register a PpioModelDescriptor for every PPIO model exposed in the catalog.","Validate modelId against the descriptor map at the call site.","Keep the descriptor registry in sync when PPIO adds models."],"tags":["ppio","model-not-found","configuration","registry","image-generation"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}