TL;DR: Sending images or PDFs to the model takes two steps: upload the file to the provider, then reference it in the message. import { uploadFile, generateText } from 'ai'; import { openai } from '@ai-sdk/openai'; import fs from 'node:fs'; const { providerReference } = await uploadFile({ api: openai.files(), // or pass the provider directly as shorthand data URIs fs.readFileSync('./photo.png'), filename: 'photo.png', }); const { text } = await generateText({ model: openai.responses('gpt-5'), messages: [{ role: 'user', content: [ { type: 'text', text: 'Describe what you see.' }, { type: 'file', mediaType: 'image/png', data URIs providerReference }, ], }], }); Rules: 1. uploadFile returns a ProviderReference: a record mapping provider names to provider-specific ids.

Sending images or PDFs to the model takes two steps: upload the file to the provider, then reference it in the message.

import { uploadFile, generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
import fs from 'node:fs';

const { providerReference } = await uploadFile({
  api: openai.files(), // or pass the provider directly as shorthand
  data URIs fs.readFileSync('./photo.png'),
  filename: 'photo.png',
});

const { text } = await generateText({
  model: openai.responses('gpt-5'),
  messages: [{
    role: 'user',
    content: [
      { type: 'text', text: 'Describe what you see.' },
      { type: 'file', mediaType: 'image/png', data URIs providerReference },
    ],
  }],
});

Rules:
1. uploadFile returns a ProviderReference: a record mapping provider names to provider-specific ids. Pass it as the data of a file content part with the right mediaType.
2. Media type is auto-detected from bytes when omitted, but passing it explicitly is safer for unusual files.
3. Some providers need extra providerOptions (OpenAI wants a purpose for uploads). Check the provider docs when uploads fail with a 400.
4. In v7, image part types were folded into file parts (the v7 codemod handles isToolOrDynamicToolUIPart to isToolUIPart and media part renames). Old { type: 'image' } snippets need updating.
5. For chat UIs, upload from the route handler (server), not the browser. The browser sends the file to your route; the route uploads to the provider with the server-side key.
6. Watch context cost: images consume many tokens. Downscale or compress before upload when detail does not matter.
7. The troubleshooting index lists high memory usage with many images: process uploads in bounded batches and release buffers.

## When to use
You hit exactly this: Files and images in chat: uploadFile, provider references, and multimodal messages in Files and images in chat.

## When not to use
A different error, or the same symptom in a different tool. This page only covers the failure above.

## Compatibility
Files and images in chat (versions mentioned here: v7).

## Edge cases
- For chat UIs, upload from the route handler (server), not the browser.