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 audio content. Pass a string or a user message whose content contains only text parts. What it means
convertHarnessPromptToACPTextBlocks throws unsupportedPromptContent when a file part's media type category is audio/*, since the ACP v1 harness supports only portable text prompts and cannot carry audio content to the agent.
Source
Thrown at packages/harness-acp/src/v1/acp-v1-prompt.ts:49
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',
});
}
throw unsupportedPromptContent({
harnessId,
category: `embedded resource content with media type ${JSON.stringify(part.mediaType)}`,
});
}
throw unsupportedPromptContent({
harnessId,
category: `content parts of type ${JSON.stringify(
(part as { readonly type?: unknown }).type,
)}`,
});
}
return content;
}View on GitHub (pinned to 69428b1f8b)
Solutions
- Transcribe the audio to text locally (e.g. with a speech-to-text model) and send the transcript as a text part.
- Strip audio parts before sending the prompt.
- Use a harness/transport that supports audio if audio input is a hard requirement.
Example fix
// before
content: [{ type: 'file', mediaType: 'audio/wav', data }]
// after
content: [{ type: 'text', text: transcriptOfAudio }] Defensive patterns
Strategy: validation
Validate before calling
const hasAudioFile = typeof prompt !== 'string' &&
typeof prompt.content !== 'string' &&
prompt.content.some(p => p.type === 'file' && p.mediaType.toLowerCase().startsWith('audio/'));
if (hasAudioFile) throw new Error('Transcribe audio to text before prompting an ACP v1 harness'); Type guard
function isAudioFilePart(part: unknown): boolean {
const p = part as { type?: string; mediaType?: string };
return p?.type === 'file' &&
typeof p.mediaType === 'string' &&
p.mediaType.toLowerCase().startsWith('audio/');
} Try / catch
try {
await session.prompt(msg);
} catch (e) {
if (String(e?.message).includes('does not support audio content')) {
await session.prompt(transcribeAudioParts(msg));
} else throw e;
} Prevention
- Run speech-to-text in the UI/adapter layer before the harness ever sees audio
- Block audio/* attachments for ACP-backed sessions
- Add mediaType allowlisting (text-only) in the prompt builder
When it happens
Trigger: Prompting an ACP v1 harness with a file part whose mediaType starts with 'audio/' (e.g. audio/wav, audio/mpeg), such as voice memos or transcribed-audio attachments.
Common situations: Voice-input chat features piping raw audio into an ACP coding-agent session.
Related errors
- The ${harnessId} ACP harness supports only portable text pro
- The ${harnessId} ACP harness supports only portable text pro
- The ${harnessId} ACP harness supports only portable text pro
- The ${model.provider} model "${model.modelId}" does not supp
- Invalid argument for parameter requests: requests must not b
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/88470d1f78cbe1e4.
Report an issue: GitHub.