{"record":{"id":"450b38df6788f5d1","repo":"can1357/oh-my-pi","slug":"resolved-model-textonly-provider-textonly-id","errorCode":null,"errorMessage":"Resolved model ${textOnly.provider}/${textOnly.id} does not support image input. Configure a vision-capable model for modelRoles.vision.","messagePattern":"Resolved model (.+?)/(.+?) does not support image input\\. Configure a vision-capable model for modelRoles\\.vision\\.","errorType":"validation","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/inspect-image.ts","lineNumber":196,"sourceCode":"\t\tlet model: Model<Api> | undefined;\n\t\tlet selectedPattern: string | undefined;\n\t\tfor (const pattern of [\"@vision\", \"@default\", activeModelPattern]) {\n\t\t\tconst resolved = resolvePattern(pattern);\n\t\t\tif (resolved?.input.includes(\"image\")) {\n\t\t\t\tmodel = resolved;\n\t\t\t\tselectedPattern = pattern;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tconst activeProvider = resolvePattern(activeModelPattern)?.provider;\n\t\tmodel ??= availableModels.find(\n\t\t\tcandidate => candidate.provider === activeProvider && candidate.input.includes(\"image\"),\n\t\t);\n\t\tmodel ??= availableModels.find(candidate => candidate.input.includes(\"image\"));\n\t\tif (!model) {\n\t\t\tconst textOnly = resolvePattern(\"@vision\") ?? resolvePattern(\"@default\") ?? resolvePattern(activeModelPattern);\n\t\t\tif (!textOnly) throw new ToolError(\"Unable to resolve a model for inspect_image.\");\n\t\t\tthrow new ToolError(\n\t\t\t\t`Resolved model ${textOnly.provider}/${textOnly.id} does not support image input. Configure a vision-capable model for modelRoles.vision.`,\n\t\t\t);\n\t\t}\n\n\t\tconst apiKey = await modelRegistry.getApiKey(model);\n\t\tif (!apiKey) {\n\t\t\tthrow new ToolError(\n\t\t\t\t`No API key available for ${model.provider}/${model.id}. Configure credentials for this provider or choose another vision-capable model.`,\n\t\t\t);\n\t\t}\n\n\t\tlet imageInput: LoadedImageInput | null;\n\t\tconst autoResize = this.session.settings.get(\"images.autoResize\");\n\t\tconst excludeWebP = webpExclusionForModel(model);\n\t\tconst attachmentReference = parseImageAttachmentReference(params.path);\n\t\tconst imageTarget = attachmentReference\n\t\t\t? undefined\n\t\t\t: await splitPathAndSelPreferringLiteral(params.path, this.session.cwd);","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/inspect-image.ts#L178-L214","documentation":"inspect_image resolved a model through @vision/@default/active-model patterns, but that model's declared input modalities do not include \"image\" — it is text-only. The tool refuses to send the image and tells you to configure a vision-capable model under modelRoles.vision.","triggerScenarios":"modelRoles.vision (or @default / the active model) resolves to a text-only model, and no other available model advertises image input (the fallback scans all availableModels for input.includes(\"image\") and found none).","commonSituations":"Pointing modelRoles.vision at a text-only model (e.g. a code model without vision); using a provider whose models.json metadata omits the image modality; running a small/local model roster with no multimodal model.","solutions":["Set modelRoles.vision to a model known to support image input (e.g. openai/gpt-4o, anthropic/claude-...-vision-capable, google/gemini-*).","Verify the chosen model's input modalities include \"image\" in the catalog/discovery output.","If a vision model exists but isn't detected, fix/refresh provider discovery or the model metadata rather than the role.","Register/connect a multimodal provider if none is available."],"exampleFix":"// before\n{ \"modelRoles\": { \"vision\": \"openai/gpt-3.5-turbo\" } }\n// after\n{ \"modelRoles\": { \"vision\": \"openai/gpt-4o\" } }","handlingStrategy":"validation","validationCode":"const vision = session.modelRegistry.getAvailable().find(m => m.input.includes(\"image\"));\nif (!vision) {\n  // no vision-capable model registered: configure one or skip image inspection\n}","typeGuard":"function isVisionCapable(m: Model<Api>): boolean {\n  return Array.isArray(m.input) && m.input.includes(\"image\");\n}","tryCatchPattern":"try {\n  await inspectImageTool.execute(id, params, signal);\n} catch (e) {\n  if (e instanceof ToolError && e.message.includes(\"does not support image input\")) {\n    // reconfigure modelRoles.vision to a multimodal model\n  } else throw e;\n}","preventionTips":["Set modelRoles.vision to a model whose input modalities include \"image\".","Check the model catalog entry before assigning a vision role.","Keep at least one known multimodal provider authenticated as a fallback."],"tags":["configuration","models","multimodal","model-capability"],"backgroundTag":"model-lacks-capability","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}