CherryHQ/cherry-studio · error · NonVisionImageOcrError

The selected model doesn't support images, and Cherry Studio

Error message

The selected model doesn't support images, and Cherry Studio couldn't extract readable text from the attachment. Choose a vision-capable model or remove the image and try again.

What it means

Intentional, user-facing error from the chat attachment router. When a non-vision model is sent an image and OCR (`ocrNonVisionImage`) returns `null` — meaning no readable text could be extracted (OCR unconfigured, failed, or image has no text) — the router throws `NonVisionImageOcrError` to STOP before the provider call, avoiding a deterministic provider-side 'model does not support images' error. The class carries `i18nKey = 'image_unreadable_for_non_vision_model'` for localization, and the prepareChatMessage catch re-throws it (it is NOT degraded to a note) so it surfaces to the user. Abort errors are re-thrown first.

Source

Thrown at src/main/ai/messages/attachmentRouting.ts:230

    const displayName = ref?.displayName ?? handle
    try {
      const bareExt = ((await application.get('FileManager').getById(fileEntryId)).ext ?? '').toLowerCase()
      const fileType = getFileTypeByExt(bareExt)

      if (isNative(bareExt, fileType, ctx.nativeSupport)) {
        if (!(await inlineNative(part))) {
          logger.warn('Native file materialization failed; degrading to note', { messageId: message.id, displayName })
          kept.push(noteOf(handle) as UIMessage['parts'][number])
        }
        continue
      }

      // Non-vision image → OCR text when it finds any. If OCR cannot produce
      // text, stop before opening a provider request: sending the native image
      // to a known non-vision model would only produce a deterministic API error.
      if (fileType === FILE_TYPE.IMAGE) {
        const ocrText = await ocrNonVisionImage(fileEntryId, ctx.signal)
        if (ocrText === null) throw new NonVisionImageOcrError()
        const text = `Attached file "${handle}":\n${capInlineText(handle, ocrText, ctx.isToolCapable, ctx.cap)}`
        kept.push({ type: 'text', text } as UIMessage['parts'][number])
        continue
      }

      // Non-native first-party attachment → inline its (capped) text.
      const body = await extractNonNativeText(fileEntryId, bareExt, fileType, handle, ctx.signal)
      const text = `Attached file "${handle}":\n${capInlineText(handle, body, ctx.isToolCapable, ctx.cap)}`
      kept.push({ type: 'text', text } as UIMessage['parts'][number])
    } catch (error) {
      if (ctx.signal?.aborted || isAbortError(error)) throw error
      if (error instanceof NonVisionImageOcrError) throw error
      logger.error('Failed to prepare attached file', error as Error, { messageId: message.id, displayName })
      kept.push(noteOf(handle) as UIMessage['parts'][number])
    }
  }

  return { ...message, parts: kept } as T

View on GitHub (pinned to 726446b54c)

Solutions

  1. Switch to a vision-capable model for this conversation.
  2. Remove the image and re-send, or attach a text excerpt instead.
  3. Enable/configure OCR so non-vision models can fall back to extracted text.
  4. If the image contains text, ensure OCR is reachable and retry.
Defensive patterns

Strategy: fallback

Validate before calling

// Before sending, route attachments by model capability.
function classifyImageAttachment(modelSupportsVision: boolean, ocrAvailable: boolean, imageHasText: boolean | null) {
  if (modelSupportsVision) return 'native'           // send the image as-is
  if (ocrAvailable && imageHasText) return 'ocr-text' // inline extracted text
  return 'blocked'                                    // NonVisionImageOcrError will fire
}

Type guard

// Detect the error by name/i18nKey when it propagates:
const isNonVisionImageOcrError = (e: unknown): boolean =>
  e instanceof Error && (e.name === 'NonVisionImageOcrError' ||
    (e as any).i18nKey === 'image_unreadable_for_non_vision_model')

Try / catch

try {
  await prepareChatMessages(messages, ctx)
} catch (e) {
  if (isNonVisionImageOcrError(e)) {
    // surface the i18nKey to the user; offer: switch to a vision model, remove the image, or enable OCR
  } else if (isAbortError(e)) {
    throw e
  }
  // other attachment failures degrade to a note inside prepareChatMessages and do not reach here
}

Prevention

When it happens

Trigger: Sending an image attachment to a model whose capabilities exclude vision, while OCR is unavailable/disabled or yields no text from that image.

Common situations: User attaches a screenshot to a text-only model with OCR off or OCR service misconfigured; the image is purely graphical (no text); OCR API key/endpoint missing.


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/33faaa6ae3f4a6f6. Report an issue: GitHub.