vercel/ai · error · HarnessCapabilityUnsupportedError

The ${harnessId} ACP harness supports only portable text pro

Error message

The ${harnessId} ACP harness supports only portable text prompts and does not support image content. Pass a string or a user message whose content contains only text parts.

What it means

convertHarnessPromptToACPTextBlocks rejects prompts containing image content parts. The ACP v1 harness only supports portable text prompts, so any prompt whose message content includes an image part causes this unsupportedPromptContent error before the prompt is sent to the agent.

Source

Thrown at packages/harness-acp/src/v1/acp-v1-prompt.ts:35

}: {
  prompt: HarnessV1Prompt;
  harnessId: string;
}): ACPTextContentBlock[] {
  if (typeof prompt === 'string') {
    return [{ type: 'text', text: prompt }];
  }
  if (typeof prompt.content === 'string') {
    return [{ type: 'text', text: prompt.content }];
  }

  const content: ACPTextContentBlock[] = [];
  for (const part of prompt.content) {
    if (part.type === 'text') {
      content.push({ type: 'text', text: part.text });
      continue;
    }
    if (part.type === 'image') {
      throw unsupportedPromptContent({
        harnessId,
        category: 'image content',
      });
    }
    if (part.type === 'file') {
      const mediaCategory = part.mediaType.toLowerCase().split('/', 1)[0];
      if (mediaCategory === 'image') {
        throw unsupportedPromptContent({
          harnessId,
          category: 'image content',
        });
      }
      if (mediaCategory === 'audio') {
        throw unsupportedPromptContent({
          harnessId,
          category: 'audio content',
        });
      }

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Send a plain string prompt or a user message whose content contains only text parts.
  2. Describe or OCR the image into a text part before prompting.
  3. Filter or reject image parts in your UI/adapter layer before they reach the harness.

Example fix

// before
await prompt({ content: [{ type: 'text', text: 'What is this?' }, { type: 'image', image: buf }] });
// after
await prompt({ content: [{ type: 'text', text: 'What is this? (describe the screenshot in words)' }] });
Defensive patterns

Strategy: validation

Validate before calling

const hasImage = typeof prompt !== 'string' &&
  typeof prompt.content !== 'string' &&
  prompt.content.some(p => p.type === 'image');
if (hasImage) throw new Error('ACP v1 harness prompts must contain only text parts');

Type guard

function isTextOnlyPrompt(p: unknown): boolean {
  if (typeof p === 'string') return true;
  const q = p as { content?: unknown };
  if (typeof q.content === 'string') return true;
  return Array.isArray(q.content) &&
    q.content.every((part: any) => part?.type === 'text');
}

Try / catch

try {
  await session.prompt(msg);
} catch (e) {
  if (String(e?.message).includes('does not support image content')) {
    await session.prompt(toTextOnly(msg));
  } else throw e;
}

Prevention

When it happens

Trigger: Prompting an ACP v1 harness session with a user message whose content array contains a part with type: 'image', or any non-string prompt that resolves to image parts.

Common situations: Reusing a multimodal chat pipeline (screenshots, image uploads) against an ACP coding-agent harness; passing through user attachments unfiltered.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/d8cbe4ec39e35d2c. Report an issue: GitHub.