{"record":{"id":"1fb581d798b0787f","repo":"paperclipai/paperclip","slug":"pi-requires-adapterconfig-model-in-provider-mode","errorCode":null,"errorMessage":"Pi requires `adapterConfig.model` in provider/model format.","messagePattern":"Pi requires `adapterConfig\\.model` in provider/model format\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/adapters/pi-local/src/server/models.ts","lineNumber":177,"sourceCode":"  const now = Date.now();\n  pruneExpiredDiscoveryCache(now);\n  const cached = discoveryCache.get(key);\n  if (cached && cached.expiresAt > now) return cached.models;\n\n  const models = await discoverPiModels({ command, cwd, env });\n  discoveryCache.set(key, { expiresAt: now + MODELS_CACHE_TTL_MS, models });\n  return models;\n}\n\nexport async function ensurePiModelConfiguredAndAvailable(input: {\n  model?: unknown;\n  command?: unknown;\n  cwd?: unknown;\n  env?: unknown;\n}): Promise<AdapterModel[]> {\n  const model = asString(input.model, \"\").trim();\n  if (!model) {\n    throw new Error(\"Pi requires `adapterConfig.model` in provider/model format.\");\n  }\n\n  const models = await discoverPiModelsCached({\n    command: input.command,\n    cwd: input.cwd,\n    env: input.env,\n  });\n\n  if (models.length === 0) {\n    throw new Error(\"Pi returned no models. Run `pi --list-models` and verify provider auth.\");\n  }\n\n  if (!models.some((entry) => entry.id === model)) {\n    const sample = models.slice(0, 12).map((entry) => entry.id).join(\", \");\n    throw new Error(\n      `Configured Pi model is unavailable: ${model}. Available models: ${sample}${models.length > 12 ? \", ...\" : \"\"}`,\n    );\n  }","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/adapters/pi-local/src/server/models.ts#L159-L195","documentation":"Thrown by ensurePiModelConfiguredAndAvailable (pi-local) when adapterConfig.model is empty after trimming. Unlike the OpenCode validator (392), this check only rejects emptiness — it does not enforce a provider/model slash format; the format expectation in the message is advisory. The function then proceeds to discovery.","triggerScenarios":"asString(input.model, \"\").trim() is empty when ensurePiModelConfiguredAndAvailable is called.","commonSituations":"adapterConfig.model never set for a Pi-backed agent; the field was cleared by a config edit/migration; the model was passed as undefined or whitespace.","solutions":["Set adapterConfig.model to a non-empty model id that pi recognizes.","Run `pi --list-models` to find valid model ids, then assign one.","If generating config programmatically, default model to a known-good id."],"exampleFix":"// before\nadapterConfig = { /* model missing */ }\n// after\nadapterConfig = { model: \"<provider>/<model>\" }","handlingStrategy":"type-guard","validationCode":"const model = asString(adapterConfig.model, \"\").trim();\nif (!model) {\n  throw new Error(\"adapterConfig.model is required for the Pi adapter before starting the run.\");\n}","typeGuard":"function hasPiModel(input: { model?: unknown }): input is { model: string } {\n  return typeof input.model === \"string\" && input.model.trim().length > 0;\n}","tryCatchPattern":null,"preventionTips":["Set adapterConfig.model at agent creation; reject empty in config schemas.","Populate model options from `pi --list-models` in the UI.","Default to a known-good model id when generating config programmatically."],"tags":["pi","models","validation","configuration"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}