{"record":{"id":"c8ee3926cfbe30b2","repo":"paperclipai/paperclip","slug":"opencode-requires-adapterconfig-model-in-provide","errorCode":null,"errorMessage":"OpenCode requires `adapterConfig.model` in provider/model format.","messagePattern":"OpenCode requires `adapterConfig\\.model` in provider/model format\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/adapters/opencode-local/src/server/models.ts","lineNumber":30,"sourceCode":"const MODELS_DISCOVERY_TIMEOUT_MS = 20_000;\n\nfunction resolveOpenCodeCommand(input: unknown): string {\n  const envOverride =\n    typeof process.env.PAPERCLIP_OPENCODE_COMMAND === \"string\" &&\n    process.env.PAPERCLIP_OPENCODE_COMMAND.trim().length > 0\n      ? process.env.PAPERCLIP_OPENCODE_COMMAND.trim()\n      : \"opencode\";\n  return asString(input, envOverride);\n}\n\nconst discoveryCache = new Map<string, { expiresAt: number; models: AdapterModel[] }>();\nconst VOLATILE_ENV_KEY_PREFIXES = [\"PAPERCLIP_\", \"npm_\", \"NPM_\"] as const;\nconst VOLATILE_ENV_KEY_EXACT = new Set([\"PWD\", \"OLDPWD\", \"SHLVL\", \"_\", \"TERM_SESSION_ID\", \"HOME\"]);\n\nexport function requireOpenCodeModelId(input: unknown): string {\n  const model = asString(input, \"\").trim();\n  if (!isValidOpenCodeModelId(model)) {\n    throw new Error(\"OpenCode requires `adapterConfig.model` in provider/model format.\");\n  }\n  return model;\n}\n\nfunction dedupeModels(models: AdapterModel[]): AdapterModel[] {\n  const seen = new Set<string>();\n  const deduped: AdapterModel[] = [];\n  for (const model of models) {\n    const id = model.id.trim();\n    if (!id || seen.has(id)) continue;\n    seen.add(id);\n    deduped.push({ id, label: model.label.trim() || id });\n  }\n  return deduped;\n}\n\nfunction sortModels(models: AdapterModel[]): AdapterModel[] {\n  return [...models].sort((a, b) =>","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/adapters/opencode-local/src/server/models.ts#L12-L48","documentation":"Thrown by requireOpenCodeModelId (models.ts) when adapterConfig.model is missing or fails isValidOpenCodeModelId. OpenCode addresses models as provider/model (e.g. 'anthropic/claude-3-5-sonnet'), and the validator enforces that shape before any discovery runs, so an empty or slash-less value is rejected up front.","triggerScenarios":"requireOpenCodeModelId(input.model) is called with input.model undefined, empty after trim, or not matching the provider/model regex.","commonSituations":"adapterConfig.model was never set on the agent; the model was set as a bare id ('gpt-4o') without the provider prefix; a config migration dropped the field.","solutions":["Set adapterConfig.model to a provider/model string, e.g. 'openai/gpt-4o' or 'anthropic/claude-3-5-sonnet'.","Confirm the provider segment matches a provider opencode knows (run `opencode models` to see valid prefixes).","If the model id is generated dynamically, validate it with isValidOpenCodeModelId before assigning."],"exampleFix":"// before\nadapterConfig = { model: \"gpt-4o\" }\n// after\nadapterConfig = { model: \"openai/gpt-4o\" }","handlingStrategy":"type-guard","validationCode":"const model = asString(adapterConfig.model, \"\").trim();\nif (!isValidOpenCodeModelId(model)) {\n  throw new Error(\"adapterConfig.model must be set in provider/model format before starting the run.\");\n}","typeGuard":"function isOpenCodeModelId(value: unknown): value is string {\n  return typeof value === \"string\" && isValidOpenCodeModelId(value.trim());\n}","tryCatchPattern":null,"preventionTips":["Always set adapterConfig.model as provider/model at agent creation.","Validate with isValidOpenCodeModelId in config schemas before persisting.","Reject bare model ids in the UI/config layer early."],"tags":["opencode","models","validation","configuration"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}