{"record":{"id":"24e3b620652e2599","repo":"Mintplex-Labs/anything-llm","slug":"ppio-chat-this-model-is-not-valid-for-chat-com","errorCode":null,"errorMessage":"PPIO chat: ${this.model} is not valid for chat completion!","messagePattern":"PPIO chat: (.+?) is not valid for chat completion!","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/utils/AiProviders/ppio/index.js","lineNumber":150,"sourceCode":"  }\n\n  constructPrompt({\n    systemPrompt = \"\",\n    contextTexts = [],\n    chatHistory = [],\n    userPrompt = \"\",\n    // attachments = [], - not supported\n  }) {\n    const prompt = {\n      role: \"system\",\n      content: `${systemPrompt}${this.#appendContext(contextTexts)}`,\n    };\n    return [prompt, ...chatHistory, { role: \"user\", content: userPrompt }];\n  }\n\n  async getChatCompletion(messages = null, { temperature = 0.7 }) {\n    if (!(await this.isValidChatCompletionModel(this.model)))\n      throw new Error(\n        `PPIO chat: ${this.model} is not valid for chat completion!`\n      );\n\n    const result = await LLMPerformanceMonitor.measureAsyncFunction(\n      this.openai.chat.completions\n        .create({\n          model: this.model,\n          messages,\n          temperature,\n        })\n        .catch((e) => {\n          throw new Error(e.message);\n        })\n    );\n\n    if (\n      !Object.prototype.hasOwnProperty.call(result.output, \"choices\") ||\n      result.output.choices.length === 0","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/526360e320da9d1b36074be5ed64fe76e5bbfbbd/server/utils/AiProviders/ppio/index.js#L132-L168","documentation":"Thrown by PPIOLLM.getChatCompletion when isValidChatCompletionModel(this.model) is false. Unlike the static Perplexity list, PPIO calls #syncModels() (which fetches the live /v3/openai/models list, caching to storage/models/ppio) and then checks the model is present — so this fails when the id is not in the freshly synced set.","triggerScenarios":"this.model is not returned by PPIO's models endpoint: a typo, a model the account cannot access, a model id that was retired, or #syncModels failed silently and the cache is empty/stale.","commonSituations":"PPIO_MODEL_PREF points at a model removed from the catalog; first run when storage/models/ppio cache is empty and the sync fetch returned an unexpected payload; passing a text model id to a vision-only endpoint name; the account tier does not include the requested model.","solutions":["Inspect the cached list at storage/models/ppio (or call GET https://api.ppinfra.com/v3/openai/models with the key) and set this.model to an id present there.","Delete the stale storage/models/ppio cache so #syncModels repopulates on next call.","Clear PPIO_MODEL_PREF and re-select the model in the UI.","Verify the key's plan includes the model on the PPIO dashboard."],"exampleFix":"// before\nconst llm = new PPIOLLM(embedder, \"deepseek/deepseek-r1\"); // not in synced set\nawait llm.getChatCompletion(messages, { temperature: 0.7 });\n\n// after\nconst known = await llm.isValidChatCompletionModel(\"deepseek/deepseek-r1\");\nconst model = known ? \"deepseek/deepseek-r1\" : \"qwen/qwen2.5-32b-instruct\";\nconst llm2 = new PPIOLLM(embedder, model);\nawait llm2.getChatCompletion(messages, { temperature: 0.7 });","handlingStrategy":"validation","validationCode":"// PPIO's check is async because it syncs the catalog first\nconst valid = await llm.isValidChatCompletionModel(llm.model);\nif (!valid) {\n  const fallback = \"qwen/qwen2.5-32b-instruct\";\n  llm = new PPIOLLM(embedder, fallback);\n  if (!(await llm.isValidChatCompletionModel(llm.model))) {\n    throw new Error(`PPIO has no usable model for this key (sync may have failed)`);\n  }\n}","typeGuard":"async function isKnownPpioModel(llm, id) {\n  return typeof id === \"string\" && (await llm.isValidChatCompletionModel(id));\n}","tryCatchPattern":"try {\n  return await llm.getChatCompletion(messages, opts);\n} catch (e) {\n  if (/not valid for chat completion/i.test(e.message)) {\n    llm.model = \"qwen/qwen2.5-32b-instruct\";\n    return llm.getChatCompletion(messages, opts);\n  }\n  throw e;\n}","preventionTips":["Always pass a known-good modelPreference from the UI dropdown rather than a free-text env value.","If #syncModels can fail, log its result so an empty cache does not look like 'all models invalid'.","Treat storage/models/ppio as a cache that can be deleted; do not rely on it being populated.","Confirm the account plan includes the model on the PPIO dashboard before configuring."],"tags":["validation","model-selection","llm-provider","ppio","chat-completion"],"backgroundTag":null,"analyzedSha":"526360e320da9d1b36074be5ed64fe76e5bbfbbd","analyzedAt":"2026-08-13T01:45:47.170Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}